2017-09-22 9 views
0

これは、初めてICommandをデータバインドしようとするときです。 Iデジタルは、私はボタンのように行動したいLED制御、私はLEDのように見えるように、ButtonコントロールのためのDataTemplateを変更しました:複数のボタンをクリックした後のICommandの「フリーズ」のWPFデータバインド

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> 

そこには-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の呼び出しが停止します。どうして?

+1

あなたの 'LED'コントロールは' UserControl'から取り除かれ、 'DataTemplate'で使われることができます。なぜなら、UCはかなり高価だからです。とにかく 'DataTemplate'であなたが使用したいバインディングが利用可能になります。また、バインディング 'xmlns:diag =" clr-namespace:System.Diagnostics; assembly = WindowsBase "' thenLEDClicked = "{Binding Clicked、diag:PresentationTraceSources.TraceLevel = High}"に関する情報を取得しようとします。 – XAMlMAX

+2

@ XAMlMAX私は、事実、PresentationTraceSourcesのネームスペースは実際には必要ではないことを知った。ちょうど 'PresentationTraceSources.TraceLevel = High'がうまく動作する。毎回ネームスペース属性のコピーを見つけるのに苦労します。 –

+0

@XAMIMAX問題が解消されたかどうかを確認しようとします。なぜ私がここに提示した質問がとても悪くて-1になったのだろうかと思います。 – Dave

答えて

0

私は技術的な推論を理解していませんが、私は幸運にも「凍結」問題の解決策を見つけ出しました。

私のDigitalInputDataコンストラクタでは、ハンドラへの参照を渡す代わりに、ラムダ関数を使ってRelayCommandのハンドラを作成しました。 RelayCommandコンストラクタにハンドラを渡すように切り替えると、うまくいった。