2012-04-23 21 views
5

EDIT2: Grafik dolduğunda artık değerleri değiştiremiyorum. Listedeki değerleri değiştirdiğimde (ItemControls değerlerini nereden alır), grafik yeni değerlerle güncellenmiyor gibi görünüyor.Databinding ItemsControl (DataTemplate) güncellenmiyor/program başlangıcındaki değerleri alıyor

Grafikimi her x saniyede bir güncellemek için zamanlayıcıda GetDataGrafiek() yöntemini çağırıyorum.

 Grafiek graf = new Grafiek(); 
     graf.GetDataGrafiek(); 

bunun nedeni Threading Timer ayrı bir konu çalıştıran (IsAsynchronousObjectDataProvider yılında yöntemi) veya mı benim zamanlayıcı yönteminde ItemsControl DataContext erişmek gerekir?

DÜZENLEME:

public static ObservableCollection<GrafiekBar> listGrafiek = new ObservableCollection<GrafiekBar>() 
     { 
      new GrafiekBar() {Value = 0, Fill = (Brush)convertor.ConvertFromString(kleuren[0])}, 
      new GrafiekBar() {Value = 0, Fill = (Brush)convertor.ConvertFromString(kleuren[1])}, 
      new GrafiekBar() {Value = 0, Fill = (Brush)convertor.ConvertFromString(kleuren[2])} 
     }; 
:
ben program zaten bu yüzden koşuyordu ı ObservableCollection<GrafiekBar> statik (çubukların Doldur ve Değerini tutan listeyi) yapılan grafiği doldurmamız mümkün edemedi ve başlatıldı aşağıdaki gibidir

MSDN: ObjectDataProvider: "Ancak, önceden oluşturulmuş bir nesneye bağlanıyorsanız, aşağıdaki örnekte olduğu gibi, DataContext'i kod olarak ayarlamanız gerekir."


basit bir çubuk grafik olarak görüntülenen bir ItemsControl sahiptir. Değerlerimi atarken (codeBehind kodumda kodlanmış) grafik başarılı bir şekilde doldurulur.

Temel olarak, en büyük değeri% 100 olarak ayarlamak ve kalan çubukların kalan uzunluğunu hesaplamak.

Sorun: Grafik çubuğu değerlerinin kodlamasını istemiyorum ancak çubukların runTime değerini değiştirmek zorundayım. Bunun için programımın çalışmakta olduğu her saniye çalışan bir Threading.Timer kullanın (diğer hesaplamalar bu zamanlayıcıda da olur).

Grafik çubuk değerleri, bu zamanlayıcıda gerçekleşen hesaplamalara göre her x saniyede bir güncelleme alır.

Her şeyi denedim ve programım çalışırken değerleri gösteremiyorum. Sadece barkodlarını okuduğumda çubukları görebilirim (iş parçasının sonunda GetDataGrafiek() bölgesine bakın). Tam olarak ne yanlış/eksik yapıyorum?

GetDataGrafiek() (grafiğimi doldurmak için hesaplamalar), ObjectDataProvider numaralı telefondan çağrılır.

Bu yöntem, girdi olarak TimeSpan'ı alır ve daha sonra hesaplamalar yapar, böylece bir Double Value (yukarıda açıklanan% 100 değerine dayanarak) elde edersiniz, bu da çubuğun Değerine yerleştirilir (= dateTemplate genişliği).Benim ItemsControl için

<ObjectDataProvider x:Key="odpLbGrafiek" ObjectType="{x:Type myClasses:GrafiekBar}" MethodName="GetDataGrafiek"/> 

DataTemplate (bu Haritamda çubuklarının değeri genişliği kullanır)

<DataTemplate x:Key="GrafiekItemTemplate"> 
     <Border Width="Auto" Height="Auto"> 
      <Grid> 
       <Rectangle StrokeThickness="0" Height="30" 
          Margin="15" 
          HorizontalAlignment="Right" 
          VerticalAlignment="Bottom" 
          Width="{Binding Value}" 
          Fill="{Binding Fill}"> 
        <Rectangle.LayoutTransform> 
         <ScaleTransform ScaleX="20" /> 
        </Rectangle.LayoutTransform> 
       </Rectangle> 
      </Grid> 
     </Border> 
    </DataTemplate> 

ItemsControl:

<ItemsControl x:Name="icGrafiek" 
      Margin="50,3,0,0" 
      ItemsSource="{Binding Source={StaticResource odpLbGrafiek}}" 
      ItemTemplate="{DynamicResource GrafiekItemTemplate}" 
      RenderTransformOrigin="1,0.5" HorizontalAlignment="Left" VerticalAlignment="Top" Grid.RowSpan="6"> 
      <ItemsControl.RenderTransform> 
       <TransformGroup> 
        <ScaleTransform ScaleY="-1" ScaleX="1"/> 
        <SkewTransform AngleY="0" AngleX="0"/> 
        <RotateTransform Angle="180"/> 
        <TranslateTransform/> 
       </TransformGroup> 
      </ItemsControl.RenderTransform> 
     </ItemsControl> 

GetDataGrafiek() Bölge bittiğinde, bölge kodlanmış değerleri tutar grafiğimde 6 çubuk başarıyla görüntülenir. Bölgeye yorum yaptığımda artık herhangi bir görünür çubuk almıyorum.

Bu yöntem, Double değerleriyle bir liste döndürür. Her değer, DataTemplate'da Genişlik olarak temsil edilen bir çubuğu temsil eder ve Dolgu sadece belirli bir renk verir.

ObservableCollection<GrafiekBar> listGrafiek = new ObservableCollection<GrafiekBar>(); 

    public ObservableCollection<GrafiekBar> GetDataGrafiek() 
    { 
     var converter = new System.Windows.Media.BrushConverter(); 

     #region ***TEST HARDCODED BAR VALUES*** 
      int[] testWaardenUren = new int[] { 2, 1, 0, 1, 2, 0 }; 
      int[] testWaardenMinuten = new int[] { 58, 2, 55, 55, 2, 20 }; 

      for (int j = 0; j < 6; j++) 
      { 
       TimeSpan ts = new TimeSpan(testWaardenUren[j], testWaardenMinuten[j], 0); 
       GlobalObservableCol.regStilstanden[j].Value = ts; 
       GlobalObservableCol.regStilstanden[j].Name = ""; 
      } 
     #endregion 

     totalMinutesMaxValue = GetLargestValueStilstanden(); //= "100%" value 

     //calculate % of stilstanden Values 
     for (int i = 0; i < GlobalObservableCol.regStilstanden.Count; i++) 
     { 
      Double totalMin = GlobalObservableCol.regStilstanden[i].Value.TotalMinutes; 
      totalMin = totalMin/totalMinutesMaxValue * 10; 
      valuesChartPercentage.Add(totalMin); 
     } 

     //the barChart (itemsControl) gets its final values here 
     for (int j = 0; j < GlobalObservableCol.regStilstanden.Count; j++) 
     { 
      GrafiekBar bar = new GrafiekBar(); 
      bar.Value = valuesChartPercentage[j]; 
      bar.Fill = converter.ConvertFromString(kleuren[j]) as Brush; 
      listGrafiek.Add(bar); 
     } 

     return listGrafiek; 
    } 

GrafiekBar.cls

public class GrafiekBar : INotifyPropertyChanged 
{ 
    private double value; 
    private Brush fill; 

    public GrafiekBar() 
    {  
    } 

    public double Value 
    { 
     get { return this.value; } 

     set 
    { 
      this.value = value; 
      NotifyPropertyChanged("Value"); 
     } 
    } 

    public Brush Fill 
    { 
     get { return this.fill; } 

     set 
     { 
      this.fill = value; 
      NotifyPropertyChanged("Fill"); 
     } 
    } 

    //interface INotifyPropertyChanged 
    public event PropertyChangedEventHandler PropertyChanged; 

    //interface INotifyPropertyChanged 
    private void NotifyPropertyChanged(String info) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(info)); 
     } 
    } 
} 

güncellemeler için GUI evreye bir çağırmak orada yapar denilen (yani hesaplama mantığını ve getDataGrafiek (vardır) her saniye çalışır Threading zamanlayıcısı.

private void MyTimerCallBack(object state) 
    { 
     DisplayWegingInfo(); 

     App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Background, 
      new Action(() => 
      { 
       //actions that involve updating the UI 
       CaculateTimeBetweenWegingen(); 
      })); 
    } 

Saygılarımızla Peter.

+0

Burada ne yaptığınızı takip ettiğimden emin değilim, ancak bir zamanlayıcıya sahip olmak çok tuhaf geliyor. Bunun yerine etkinliklere cevap veremez misin? – Oliver

+0

Grafik, o zamanlayıcıda her saniyede gerçekleşen hesaplamalara bağlı olarak değişmeli (veya gerekli değilse değiştirilmemelidir). Bunu nasıl çözeceğime gerçekten emin değilim. – PeterP

+0

Sadece kaba bir tahmin: Normal bir Zamanlayıcı yerine DispatcherTimer kullanmayı denediniz mi? Bu zamanlayıcı, WPF'nin – SvenG

cevap

0

Karanlıkta bir atış, çünkü tüm kodunuzu okumadım, ama burada bir düşünce var: Statik bir kaynağa bağlı değil misiniz? Bir kez okunuyor ve bu da öyle mi? Bunun yerine DynamicResource'ı deneyin. (Bu olay abone değilse) Dispatcher Konu neden olacak bir olay yükseltecek diğer iplik gibi

private void NotifyPropertyChanged(String info) 
{ 
    PropertyChangedEventHandler handler = PropertyChanged; 
    if (PropertyChanged != null) 
    { 
     PropertyChanged(this, new PropertyChangedEventArgs(info)); 
    } 
} 

: Başka bir iş parçacığı aşağıdaki kod erişiyorsanız

+0

Ah, boşver, bu aptalca bir fikirdi. Tam olarak CaculateTimeBetweenWegingen() ne yapar? yap? –

0

, bu sorunu neden olur hataya

Eğer WPF UpdateSourceMethod = PropertyChanged kullandığınızdan emin olun, aynı zamanda yerine

private void NotifyPropertyChanged(String info) 
{ 
    PropertyChangedEventHandler handler = PropertyChanged; 
    if (PropertyChanged != null) 
    { 
     if (System.Threading.Thread.CurrentThread == System.Windows.Application.Current.Dispatcher.Thread) 
      PropertyChanged(this, new PropertyChangedEventArgs(info)); 
     else 
      System.Windows.Application.Current.Dispatcher.BeginInvoke(new Action(() => PropertyChanged(this,new PropertyChangedEventArgs(info)); 
    } 
} 

deneyin.

+0

Ayrıca, gerçekten anlamadığım bir şey de, işleyicinin amacı. Doğrudan WPF'den bağlanıyorsanız, işleyiciye ihtiyacınız yoktur, yalnızca UpdateSourceMethod = Özellik, XAML'de bağlanır. – William