Xaml name scope
I need to change Rectangle attribute from C# (his RotateTransform angle)
The problem is the rectangle was declared in XAML, and in the C# code is out of scope for the rectangle, I tried to use Name, and X:Name without succeed,
How should I do it?
-------------Edit--------------------
<ContentControl Width="5" Height="400" Canvas.Top="80" Canvas.Left="350"
Template="{StaticResource DesignerItemTemplateLine}">
<Rectangle Fill="Blue" IsHitTestVisible="False" Name="mRect">
<Rectangle.RenderTransform>
<TransformGroup>
<RotateTransform Angle="45"/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
</ContentControl>
C# code
private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
Control designerItem = this.DataContext as Control;
if (designerItem != null)
{
double left = Canvas.GetLeft(designerItem);
double top = Canvas.GetTop(designerItem);
if (mRect != null)// This line don't compile
Canvas.SetLeft(designerItem, left + e.HorizontalChange);
Canvas.SetTop(designerItem, top + e.HorizontalChange);
//Canvas.SetTop(designerItem, top + e.VerticalChange);
}
}
You can notice that "if (mRect != null)" does not pass compilation
-------------Seconde Edit--- All the code----------------------------
<Window x:Class="DiagramDesigner.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="clr-namespace:DiagramDesigner"
WindowStartupLocation="CenterScreen"
Title="Move"
Height="550" Width="750">
<!-- MoveThumb Template -->
<ControlTemplate x:Key="MoveThumbTemplate" TargetType="{x:Type s:MoveThumbUpDwon}">
<Rectangle Fill="Transparent"/>
</ControlTemplate>
<!-- MoveThumb Template -->
<ControlTemplate x:Key="MoveThumbTemplateLeftRight" TargetType="{x:Type s:MoveThumbLeftRight}">
<Rectangle Fill="Transparent"/>
</ControlTemplate>
<!-- MoveThumb Template -->
<ControlTemplate x:Key="MoveLineTemplate" TargetType="{x:Type s:MoveLine}">
<Rectangle Fill="Black">
<Rectangle.RenderTransform>
<TransformGroup>
<RotateTransform Angle="45"/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
</ControlTemplate>
<!-- Designer Item Template-->
<ControlTemplate x:Key="DesignerItemTemplate" TargetType="ContentControl">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<s:MoveThumbUpDwon Template="{StaticResource MoveThumbTemplate}" Cursor="SizeAll"/>
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="DesignerItemTemplateLeftRight" TargetType="ContentControl">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<s:MoveThumbLeftRight Template="{StaticResource MoveThumbTemplateLeftRight}" Cursor="SizeAll"/>
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="DesignerItemTemplateLine" TargetType="ContentControl">
<Grid DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}">
<s:MoveLine Template="{StaticResource MoveLineTemplate}" Cursor="SizeAll"/>
<ContentPresenter Content="{TemplateBinding ContentControl.Content}"/>
</Grid>
</ControlTemplate>
</Window.Resources>
<Canvas>
<ContentControl Width="600"
Height="5"
Canvas.Top="250"
Canvas.Left="80"
Template="{StaticResource DesignerItemTemplate}">
<Rectangle Fill="Blue"
IsHitTestVisible="False"/>
</ContentControl>
<ContentControl Width="5"
Height="400"
Canvas.Top="80"
Canvas.Left="350"
Template="{StaticResource DesignerItemTemplateLeftRight}">
<Rectangle Fill="Blue"
IsHitTestVisible="False"/>
</ContentControl>
<ContentControl Width="5" Height="400" Canvas.Top="80" Canvas.Left="350"
Template="{StaticResource DesignerItemTemplateLine}">
<Rectangle Fill="Blue" IsHitTestVisible="False" Name="mRect">
<Rectangle.RenderTransform>
<TransformGroup>
<RotateTransform Angle="45"/>
</TransformGroup>
</Rectangle.RenderTransform>
</Rectangle>
</ContentControl>
</Canvas>
Now the C# code
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Shapes;
using System.Windows.Media;
using System.Windows;
namespace DiagramDesigner
{
public class MoveThumbUpDwon : Thumb
{
public MoveThumbUpDwon()
{
DragDelta += new DragDeltaEventHandler(this.MoveThumb_DragDelta);
}
private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
Control designerItem = this.DataContext as Control;
if (designerItem != null)
{
double left = Canvas.GetLeft(designerItem);
double top = Canvas.GetTop(designerItem);
//Canvas.SetLeft(designerItem, left + e.HorizontalChange);
Canvas.SetTop(designerItem, top + e.VerticalChange);
}
}
}
public class MoveThumbLeftRight : Thumb
{
public MoveThumbLeftRight()
{
DragDelt开发者_如何学JAVAa += new DragDeltaEventHandler(this.MoveThumb_DragDelta);
}
private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
Control designerItem = this.DataContext as Control;
if (designerItem != null)
{
double left = Canvas.GetLeft(designerItem);
double top = Canvas.GetTop(designerItem);
Canvas.SetLeft(designerItem, left + e.HorizontalChange);
//Canvas.SetTop(designerItem, top + e.VerticalChange);
}
}
}
public class MoveLine : Thumb
{
public MoveLine()
{
DragDelta += new DragDeltaEventHandler(this.MoveThumb_DragDelta);
}
private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
Control designerItem = this.DataContext as Control;
if (designerItem != null)
{
double left = Canvas.GetLeft(designerItem);
double top = Canvas.GetTop(designerItem);
// if (mRect != null)
Canvas.SetLeft(designerItem, left + e.HorizontalChange);
Canvas.SetTop(designerItem, top + e.HorizontalChange);
//Canvas.SetTop(designerItem, top + e.VerticalChange);
}
}
}
}
The reference is in the code-behind, but it seems to be in a different class than the xaml:
<Window x:Class="DiagramDesigner.Window1">
vs public class MoveLine : Thumb
They must be the same class if you are going to reference xaml-defined elements from the code-behind.
It looks like your window's Canvas contains a number of ContentControls. One of these is of interest and contains a grid which in turn contains firstly an instance of your MoveLine class, and secondly a ContentPresenter containing a Rectangle.
So your visual tree looks roughly like this:
Window1
Canvas
...
ContentControl
Grid
MoveLine
ContentPresenter
Rectangle (mRect)
You're trying to handle an event in MoveLine and modify the ContentPresenter's Rectangle, mRect. You can refer to mRect only in the context of Window1.
The problem is that as far as WPF is concerned the MoveLine class could appear anywhere, and so naturally it has no idea what mRect might mean to any particular MoveLine instance. As it happens we know that mRect is the child Rectangle of a sibling ContentPresenter which shares a parent with an instance of MoveLine.
If you're absolutely sure that MoveLine will only ever be used here, you could use System.Windows.Media.VisualTreeHelper's GetParent(), GetChildrenCount() and GetChild() methods. You need to go "up" one level from MoveLine, across one, and then down one. You could also go up one level and then search for descendants with the name "mName". See How can I find WPF controls by name or type?. This isn't a very sane approach though.
I'd be more tempted to put the handling code onto the canvas, or at least into its ContentControls, since they're the ones being affected. I would add a RoutedEvent called, say, ThumbMoved, to MoveLine. RoutedEvents can "bubble up" to be handled by ancestral controls. You can then add a handler for this event to the ContentControl containing your Rectangle, and it can then use mName to adjust the rectangle. See How to: Create a Custom Routed Event and How to: Handle a Routed Event. Very roughly:
class MoveLine : Thumb
{
public static readonly RoutedEvent ThumbMovedEvent =
EventManager.RegisterRoutedEvent("ThumbMoved",
RoutingStrategy.Bubble,
typeof(DragDeltaRoutedEventHandler),
typeof(MoveLine));
public event DragDeltaRoutedEventHandler ThumbMoved
{
add { AddHandler(ThumbMovedEvent, value); }
remove { RemoveHandler(ThumbMovedEvent, value); }
}
void RaiseThumbMoved(DragDeltaEventArgs e)
{
DragDeltaRoutedEventArgs newEventArgs =
new DragDeltaRoutedEventArgs(ThumbMovedEvent, e);
RaiseEvent(newEventArgs);
}
private void MoveThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
RaiseThumbMoved(e);
...
}
(Where DragDeltaRoutedEventArgs is a class derived from RoutedEventArgs which provides the same deltas as DragDeltaEventArgs.) And then in your window's XAML:
...
<ContentControl Width="5" Height="400" Canvas.Top="80" Canvas.Left="350"
Template="{StaticResource DesignerItemTemplateLine}"
MoveLine.ThumbMoved="MoveLine_ThumbMoved">
<Rectangle Fill="Blue" IsHitTestVisible="False" Name="mRect">
...
And code behind:
namespace DiagramDesigner
{
public partial class Window1 : Window
{
private void MoveLine_ThumbMoved(object sender, DragDeltaRoutedEventArgs e)
{
mRect.Foo = "Bar"; // mRect is recognised by Window1.
}
...
精彩评论