这是我第一次尝试数据绑定ICommand。我有一个数字LED控制器,我想像一个按钮,所以我改变了DataTemplate的Button控件看起来像一个LED:
LED.xaml
<UserControl x:Class="LedControlDatabindingTest.LED"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
x:Name="root"
mc:Ignorable="d"
Height="Auto" Width="Auto">
<Grid DataContext="{Binding ElementName=root}">
<StackPanel Orientation="{Binding LEDOrientation, FallbackValue=Vertical}">
<!-- LED portion -->
<Button BorderBrush="Transparent" Background="Transparent" Click="Button_Click">
<Button.ContentTemplate>
<DataTemplate>
<Grid>
<Ellipse Grid.Column="0" Margin="3" Height="{Binding ElementName=root, Path=LEDSize, FallbackValue=16}"
Width="{Binding ElementName=root, Path=LEDSize, FallbackValue=16}"
Fill="{Binding ElementName=root, Path=LEDColor, FallbackValue=Green}"
StrokeThickness="2" Stroke="DarkGray" HorizontalAlignment="Center" />
<Ellipse Grid.Column="0" Margin="3" Height="{Binding ElementName=root, Path=LEDSize, FallbackValue=16}"
Width="{Binding ElementName=root, Path=LEDSize, FallbackValue=16}" HorizontalAlignment="Center">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin="0.5,1.0">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1.5" ScaleY="1.5"/>
<TranslateTransform X="0.02" Y="0.3"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Offset="1" Color="#00000000"/>
<GradientStop Offset="0.4" Color="#FFFFFFFF"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</Grid>
</DataTemplate>
</Button.ContentTemplate>
</Button>
<!-- label -->
<TextBlock Grid.Column="1" Margin="3" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding LEDLabel, FallbackValue=0}" />
</StackPanel>
</Grid>
</UserControl>
我希望主机应用程序能够数据绑定到LED的大小,颜色和标签等属性。另外,我希望能够绑定到命令处理程序。
LED.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace LedControlDatabindingTest {
/// <summary>
/// Interaction logic for LED.xaml
/// </summary>
public partial class LED : UserControl
{
public static DependencyProperty LEDColorProperty = DependencyProperty.Register( "LEDColor", typeof(Brush), typeof(LED));
public Brush LEDColor
{
get { return this.GetValue(LEDColorProperty) as Brush; }
set {
this.SetValue( LEDColorProperty, value);
}
}
public static DependencyProperty LEDSizeProperty = DependencyProperty.Register( "LEDSize", typeof(int), typeof(LED));
public int LEDSize
{
get { return (int)GetValue(LEDSizeProperty); }
set {
SetValue( LEDSizeProperty, value);
}
}
public static DependencyProperty LEDLabelProperty = DependencyProperty.Register( "LEDLabel", typeof(string), typeof(LED));
public string LEDLabel
{
get { return (string)GetValue(LEDLabelProperty); }
set {
SetValue( LEDLabelProperty, value);
}
}
public static DependencyProperty LEDOrientationProperty = DependencyProperty.Register( "LEDOrientation", typeof(Orientation), typeof(LED));
public Orientation LEDOrientation
{
get { return (Orientation)GetValue(LEDOrientationProperty); }
set {
SetValue( LEDOrientationProperty, value);
}
}
public static readonly DependencyProperty LEDClickedProperty = DependencyProperty.Register("LEDClicked", typeof(ICommand), typeof(LED), new PropertyMetadata(null));
public ICommand LEDClicked
{
get { return (ICommand)GetValue(LEDClickedProperty); }
set { SetValue( LEDClickedProperty, value); }
}
public LED()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
LEDClicked.Execute( null);
}
}
}
我的测试应用很简单。
MainWindow.xaml:
<Window x:Class="LedControlDatabindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LedControlDatabindingTest"
Title="MainWindow" Height="70" Width="250">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<TextBlock Text="Digital Inputs:" />
<ListBox ItemsSource="{Binding AvailableDigitalInputs}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<local:LED LEDLabel="{Binding Index}" LEDColor="{Binding Color}" LEDSize="12" LEDClicked="{Binding Clicked}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</StackPanel>
</Window>
在我的代码隐藏中有这样的no-nos,就像我的应用程序的DataContext一样,但我认为就本演示而言,它现在没问题。
MainWindow.xaml.cs:
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace LedControlDatabindingTest {
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private class DigitalInputData : ViewModelBase
{
private Brush _color;
public Brush Color
{
get { return _color; }
set {
_color = value;
RaisePropertyChanged();
}
}
public int Index { get; set; }
public ICommand Clicked { get; set; }
private bool _state;
public DigitalInputData( int index, Brush on_color)
{
Index = index;
Color = Brushes.LightGray;
Clicked = new RelayCommand( () => {
// get current state of this digital input and then toggle it
_state = !_state;
// read back and update here until I get threaded updates implemented
Color = _state ? on_color : Brushes.LightGray;
});
}
}
private List<DigitalInputData> _inputs = new List<DigitalInputData>();
public ICollectionView AvailableDigitalInputs { get; set; }
public MainWindow()
{
InitializeComponent();
// For this example only, set DataContext in this way
DataContext = this;
for( int i=0; i<4; i++) {
_inputs.Add( new DigitalInputData( i, Brushes.Green));
}
AvailableDigitalInputs = CollectionViewSource.GetDefaultView( _inputs);
}
}
}
当我运行此应用程序时,所有内容都正确呈现并根据我的数据绑定属性。点击处理程序也可以工作,并切换LED的状态。
但是当我多次点击LED按钮时,某些时候(可能是经过20次点击后),它会停止调用我的数据绑定ICommand。为什么?
答案 0 :(得分:0)
我很幸运并想出了解决“冻结”问题的方法,虽然我不理解技术推理。
在我的DigitalInputData构造函数中,我使用lambda函数为RelayCommand创建了处理程序,而不是将引用传递给处理程序。一旦我切换到将处理程序传递给RelayCommand构造函数,它就运行得很好。