2013-05-30 2 views
1

방금 ​​WPF로 시작했지만 여전히 사실에 대한 모든 사실을 갖고 있지 않습니다.WPF에서 데이터 컨트롤 및 멀티 스레딩을 사용하여 기본 UI 업데이트

지금은 데이터 바인딩 및 스레딩을 사용하여 데이터를 업데이트하고이를 시간 기준으로 나타냅니다. 두 개의 텍스트 상자가있는 메인 윈도우와 그것을 클릭하면 실행을 시작하는 스레드로 정의 된 usercontrol이 있습니다. 이 스레드에서 필자는 textboxes, 코드 및 다른 xaml에 바인딩 된 기본 창에서 설정된 2 개의 속성에 대한 호출을합니다.

문제는 코드에 의해 만들어진 데이터 바인딩이 작동하는 반면, xaml로 만든 데이터 바인딩은 텍스트 상자를 직접 업데이트 할 때만 작동한다는 것입니다. 나는 왜 그런지 궁금해했고, 약간의 변화를 통해 작동하도록 만들었지 만,이 솔루션이 "정확하다"는 것은 의심 스럽습니다.

코드

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" xmlns:my="clr-namespace:WpfApplication1.Elements"> 
    <Grid> 
     <TextBox Name="Textbox1" Height="23" HorizontalAlignment="Left" Margin="188,50,0,0" VerticalAlignment="Top" Width="120" Background="White" Text="{Binding Source=my:MainWindow, Path=datavalue}" /> 
     <TextBox Name="textBox2" Background="White" Height="23" HorizontalAlignment="Left" Margin="188,101,0,0" Text="{Binding Path=datavalue2, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}} }" VerticalAlignment="Top" Width="120" /> 

     <Label Content="Label" Height="28" HorizontalAlignment="Left" Margin="202,152,0,0" Name="label1" VerticalAlignment="Top" /> 
     <my:Test Margin="81,138,346,92" x:Name="test1" /> 
    </Grid> 
</Window> 

MainWindow.xaml.cs를

namespace WpfApplication1 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window, INotifyPropertyChanged 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
     private int MydataValue; 

     public int datavalue 
     { 
      get 
      { 
       return MydataValue; 
      } 
      set 
      { 
       MydataValue = value; 

       if (PropertyChanged != null) 
       { 
        PropertyChanged(this, 
         new PropertyChangedEventArgs(
         "datavalue")); 
       } 
      } 
     } 

     private int mydatavalue2; 

     public int datavalue2 
     { 
      get 
      { 
       return mydatavalue2; 
      } 
      set{ 
       mydatavalue2 = value; 
      } 
     } 



     private void Window_Loaded(object sender, RoutedEventArgs e) 
     { 
      datavalue2 = 10; 
      datavalue = 15; 
      Binding bind = new Binding(); 
      bind.Source = this; 
      bind.Mode = BindingMode.TwoWay; 
      bind.Path = new PropertyPath("datavalue"); 
      Textbox1.SetBinding(TextBox.TextProperty, bind); 
     } 
    } 

} 

MainWindow.xaml이며 이는 해당 UserControl에게

test.xaml.cs

이다
namespace WpfApplication1.Elements 
{ 
    /// <summary> 
    /// Interaction logic for Test.xaml 
    /// </summary> 
    public partial class Test : UserControl 
    { 
     private Thread t; 
     private int resolution; 
     private Stopwatch sw,sw2; 
     private delegate void changeIconDelegate(long ib); 
     private ImageBrush b; 
     private Boolean end=false; 
     private int count = 0; 

     public Test() 
     { 
      InitializeComponent(); 
      sw = new Stopwatch(); 
      sw2 = new Stopwatch(); 
      b = new ImageBrush(); 
      resolution = 100; 
     } 

     private void UserControl_Loaded(object sender, RoutedEventArgs e) 
     { 
      b.ImageSource = new BitmapImage(new Uri("pack://application:,,,/DataBinding;component/Images/249137482.png", UriKind.Absolute)); 
      this.Background = b; 
     } 

     private void UserControl_MouseUp(object sender, MouseButtonEventArgs e) 
     { 
      t = new Thread(new ThreadStart(ThreadTask)); 
      t.Start(); 
     } 

     private void ThreadTask() 
     { 
      while (!end) 
      { 
       count = count + 1; 
       Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)delegate() 
       { 
        Application.Current.Windows.OfType<MainWindow>().First().datavalue = count; 
        Application.Current.Windows.OfType<MainWindow>().First().datavalue2 = count; 
       }); 

       Thread.Sleep((resolution - sw.Elapsed.TotalMilliseconds) > 0 ? TimeSpan.FromMilliseconds(resolution - sw.Elapsed.TotalMilliseconds):TimeSpan.FromMilliseconds(1)); 
       sw.Reset(); 
       sw.Start(); 
      } 
     } 
    } 
} 

컨트롤을 클릭하자마자 응용 프로그램을 시작하면 textbox1이 업데이트되기 시작하지만 textbox2가 직접 변경되면 변경된 알림이 throw되므로 데이터 바인딩이 제대로 수행되고 있습니다. 또는 그렇게 생각합니다.

질문은 다음과 같습니다

    해당 UserControl의 스레드에서 호출을 직접하지만 수정 한 경우
  • 가 왜 작동합니까? usercontrol은 자식이지만 xaml 파일의 textbox2 선언과 관련이 있다고 생각합니다. 그러나이 방법에 접근하는 방법을 모르겠습니다.

  • propertychanged 이벤트는 클래스의 모든 속성에 대해 작동하지만 잘못된 값을 사용하고 다른 이벤트에 대해 실수로 멀티 스레드하는 경우에는 불가능합니다.

  • 내가 WPF의 제대로 사양을 사용하지 않는 및 UserControl에서 MainWindow를 호출 할 때 어쩌면 예를 들어, 어떻게든지의 코드에 영향을 미치는 것 확신 : 큰에 대한

죄송 S를 코드와 질문의 양은 WPF를 좋아하기 시작하고 일을하지 않으면 다소 좌절감을 느낍니다. 나는 비슷한 질문을했다. 그러나 메인 UI에서 컨트롤 속성을 업데이트해야 할 때 문제가있는 것을 발견했다. 나 같은 다른 식으로는 안된다.

답변

0

몇 가지 테스트를 수행하면서 동일한 조건을 datavalue2 속성에 추가하려고 시도했다. datavalue 같이 그것을 사용할 필요가 야해 althought

 public int datavalue2 
     { 
      get 
      { 
       return mydatavalue2; 
      } 
      set{ 
       mydatavalue2 = value; 
       if (PropertyChanged != null) 
       { 
        PropertyChanged(this, 
         new PropertyChangedEventArgs(
         "datavalue2")); 
       } 
      } 
     } 

는 놀랍게도 근무 값을 업데이트 한 후 속성 변경 이벤트를 트리거, 그것을 이잖아. 이것이 직접 수정 한 경우 이것이 2 개의 이벤트를 던지기까지 약간의 비 호환성을 만들 수 있는지 궁금 해서요.하지만 제대로 작동 했으므로 하나의 이벤트 만 textbox2에 던졌습니다. 여전히이 접근 방법에 대해 불안합니다.

+0

하는 데 도움이 전혀 놀라운 일이 아니다 희망 당신의 바인더 제본 클래스를 수정할 수 있습니다. 'PropertyChanged' 이벤트를 발생시키는 것은 * 단일 *, * 특정 * 속성이 변경되었고 해당 속성에 대한 바인딩 만 업데이트된다는 것을 소비자에게 알려줍니다. 귀하의 솔루션이 정확합니다. –

+0

예, 문제는 이미 xaml에 경로와 updatesourcetrigger가 있으며 이벤트를 직접 실행하지 않고도 창에서 직접 수정하면 완벽하게 작동한다는 것입니다. 만약 내가 수동으로 이벤트를 해고하지 않는 한 그것을 할 wouldcont 아무것도 usercontrol에서 업데이 트가 – Leucaruth

+0

예 : 귀하의 텍스트 상자 컨트롤이 변경되면, 그것은 바인딩을 업데이 트하려면 알고 있기 때문에 이벤트를 발생시킵니다. 속성이 변경되면 바인딩을 업데이트 할 수 없으므로 이벤트가 발생하지 않았습니다. –

1

처음에는 절망하지 마십시오! WPF는 누구나 가파른 학습 곡선을 가지고 있습니다.

일단 속성 변경이 추가되면 올바른 방법입니다. 코드에서 변경 사항을 알리려면 UI에 알리기 위해 코드를 올려야합니다. 그러나 나는 코드가 약간 복잡하다는 것을 알았다. 유용하다고 생각하면 다른 해결책을 알려 드리겠습니다.

데이터를 클래스에 넣은 다음 xaml의 DataContext에 할당 할 수 있습니다. 이 작업을 완료하면 MVVM 패턴을 구현하는 데 매우 가깝습니다. 저의 겸허 한 견해로 WPF로 작업하는 가장 좋은 방법입니다. 난 당신이 다른 클래스를 생성하고 해당 UserControl의 DataContext에 할당 할 수 있습니다 제어한다 어린이 사용자의 경우

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <StackPanel> 
     <TextBox Text="{Binding Value1}"/> 
     <TextBox Text="{Binding Value2}"/> 
    </StackPanel> 
</Window> 

MainWindow.xaml.cs를에게 MainWindow.xaml

using System.Windows; 

namespace WpfApplication1 
{ 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 

      MyClass myClass = new MyClass(); 
      myClass.Value1 = 1; 
      myClass.Value2 = 2; 
      DataContext = myClass; 
     } 
    } 

    public class MyClass 
    { 
     public int Value1 { get; set; } 
     public int Value2 { get; set; } 
    } 
} 

일부 샘플 코드

을 넣어. 이것은 일을 함께 정리할 수 있습니다. 또한 이렇게하면 "Application.Current.Windows.OfType(). First(). datavalue = count;"를 수행 할 필요가 없습니다. 당신은 직접

그것이

+0

'Value1'이나'Value2'에 대한 변경 사항이 UI에 반영 될 경우 (즉, 질문에서 묻고있는 특정 문제) 'MyClass'에 대해'INotifyPropertyChanged'를 구현해야합니다. –

+0

그러나 MVVM이 기본이기 때문에 WPF로 작업하는 방법을 개선하는 데 도움이되므로 답변 모두를 크게 주셔서 감사합니다. :) – Leucaruth

관련 문제