[英]C# WPF Bindings not updating until MouseOut
I have a board with clickable labels (Grass and Unit), When I click a Grass label I it should move the Unit Label to the Grass's x and y position. 我有一个带有可单击标签(草和单位)的木板,当我单击草标签时,应将单位标签移到草的x和y位置。 It works, but kinda wrong. 它有效,但是有点不对。 When I click on a label, nothing happens until I move the cursor out of the clicked label, then the wanted behaviour executes. 当我单击标签时,什么都没有发生,直到我将光标移出所单击的标签,然后执行所需的行为。
XAML XAML
<local:Grass Grid.Row="9" Grid.Column="16" />
<local:Unit Grid.Row="{Binding Path=xPos, UpdateSourceTrigger=PropertyChanged}" Grid.Column="{Binding Path=yPos, UpdateSourceTrigger=PropertyChanged}" >
<local:Unit.Background>
<ImageBrush ImageSource="Images/tjej.png"/>
</local:Unit.Background>
</local:Unit>
ObjectInspector ObjectInspector
public class ObjectInspector : INotifyPropertyChanged
{
private int _xPos = 1, _yPos = 2;
public int xPos
{
get { return _xPos; }
set
{
_xPos = value;
NotifyPropertyChanged("xPos");
}
}
public int yPos
{
get { return _yPos; }
set {
_yPos = value;
NotifyPropertyChanged("yPos");
}
}
private string _type = "none";
public string type
{
get { return _type; }
set {
_type = value;
NotifyPropertyChanged("type");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
System.Diagnostics.Debug.WriteLine("property changed");
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Grass 草
public class Grass : Button
{
protected override void OnClick()
{
base.OnClick();
int x = (int)this.GetValue(Grid.RowProperty);
int y = (int)this.GetValue(Grid.ColumnProperty);
string type = this.GetType().Name;
MainWindow.objectInspector.xPos = x;
MainWindow.objectInspector.yPos = y;
MainWindow.objectInspector.type = type;
}
}
MainWindow 主窗口
public partial class MainWindow : Window
{
public static ObjectInspector objectInspector= new ObjectInspector();
public MainWindow()
{
InitializeComponent();
this.DataContext = objectInspector;
}
}
Any ideas? 有任何想法吗?
Edit Added MainWindow and Grass 编辑添加的MainWindow和Grass
EDIT 编辑
Try to register to the common event handler Click
of buttons: 尝试注册到公共事件处理程序, Click
按钮:
<local:Grass Grid.Row="9" Grid.Column="16" Click="ClickEventHandler" />
...
And take the grass element from the sender, in the event handler method. 在事件处理程序方法中,从发件人处获取grass元素。
Anyway, I think a better way for doing this is usin MVVM patter. 无论如何,我认为使用MVVM模式是更好的方法。 You may set a GrassViewModel
and UnitViewModel
. 您可以设置GrassViewModel
和UnitViewModel
。 Then create a DataTemplate
for each one. 然后为每个创建一个DataTemplate
。 For example: 例如:
<DataTemplate DataType="{x:Type ViewModel:UnitViewModel}">
...Visual Elements Here...
</DataTemplate>
The for showing the elements in a grid you may use a ListBox
with a Grid
as items panel, some like this: 用于显示网格中的元素的,您可以将ListBox
与Grid
as Items面板一起使用,如下所示:
<ListBox ItemsSource={Binding AllItemsCollection}>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
...rows and columns definitions here...
</Grid>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<!--HERE THE ITEMS STYLE, HERE YOU SET THE COLUMN, ROW BINDINGS-->
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Grid.Row" Value="{Binding yPos}"/>
<Setter Property="Grid.Column" Value="{Binding xPos}"/>
<Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Then you only need to create the AllItemsCollection
in your view model with all the elements that you want. 然后,您只需要在视图模型中使用所需的所有元素创建AllItemsCollection
。 You can handler the click event using behaviors, or creating a UserControl for the grass (and controlling the click event inside): 您可以使用行为来处理click事件,或为草创建UserControl(并在内部控制click事件):
<DataTemplate DataType="{x:Type ViewModel:UnitViewModel}">
<GrassUserControl ...Inside the grass user control you can handler the click event.../>
</DataTemplate>
Hope helps... 希望可以帮助...
If your following MVVM then you can attach a property to the label as below. 如果您使用以下MVVM,则可以按如下所示将属性附加到标签。 You can attache this behavior any control that derives from UIElement 您可以将此行为附加到任何从UIElement派生的控件
Create a Attached property for MouseClick 为MouseClick创建一个附加属性
public class MouseClick
{
public static readonly DependencyProperty MouseLeftClickProperty =
DependencyProperty.RegisterAttached("MouseLeftClick", typeof(ICommand), typeof(MouseClick),
new FrameworkPropertyMetadata(CallBack));
public static void SetMouseLeftClick(DependencyObject sender, ICommand value)
{
sender.SetValue(MouseLeftClickProperty, value);
}
public static ICommand GetMouseLeftClick(DependencyObject sender)
{
return sender.GetValue(MouseLeftClickProperty) as ICommand;
}
public static readonly DependencyProperty MouseEventParameterProperty =
DependencyProperty.RegisterAttached(
"MouseEventParameter",
typeof(object),
typeof(MouseClick),
new FrameworkPropertyMetadata((object)null, null));
public static object GetMouseEventParameter(DependencyObject d)
{
return d.GetValue(MouseEventParameterProperty);
}
public static void SetMouseEventParameter(DependencyObject d, object value)
{
d.SetValue(MouseEventParameterProperty, value);
}
private static void CallBack(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
if (sender != null)
{
UIElement element = sender as UIElement;
if (element != null)
{
if (e.OldValue != null)
{
element.RemoveHandler(UIElement.MouseDownEvent, new MouseButtonEventHandler(Handler));
}
if (e.NewValue != null)
{
element.AddHandler(UIElement.MouseDownEvent, new MouseButtonEventHandler(Handler), true);
}
}
}
}
private static void Handler(object sender, EventArgs e)
{
UIElement element = sender as UIElement;
if (sender != null)
{
ICommand cmd = element.GetValue(MouseLeftClickProperty) as ICommand;
if (cmd != null)
{
RoutedCommand routedCmd =cmd as RoutedCommand;
object paramenter = element.GetValue(MouseEventParameterProperty);
if (paramenter == null)
{
paramenter = element;
}
if (routedCmd != null)
{
if (routedCmd.CanExecute(paramenter, element))
{
routedCmd.Execute(paramenter, element);
}
}
else
{
if (cmd.CanExecute(paramenter))
{
cmd.Execute(paramenter);
}
}
}
}
}
}
In you Xaml attache the Command of your viewModel as below 在您的Xaml中,如下附加viewModel的命令
<Label Height="30" Width="200" Margin="10" Content="Click" local:MouseClick.MouseLeftClick="{Binding Click}" />
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.