2014-12-04 14 views
0

林營造賽道記分牌試圖建立一個賽道記分牌是這樣的:如何在WPF

enter image description here

的問題是,我不知道這是做的最好的做法。其實我試着創建一個不斷更新的Observable Collection。那麼問題是,當我試圖用司機最好的圈速對記分牌進行排序時,司機的位置總是靜止的。

我用一個CollectionViewSource與ListBox結合,通過屬性「BestLap」對驅動程序進行排序,但似乎驅動程序的位置僅在我第一次運行程序時排序,然後不排序。

我也嘗試在視圖模型中不斷對ObservableCollection進行排序,使Driver類IComparable並創建一個新的ObservableCollection,它將按照bestlap比較驅動程序進行排序。但它認爲這不是一個好的做法。

我想找到一個類似的樣本,但我還沒有找到它。請讓我知道如果你有任何關於如何做到這一點的建議。

對不起,我的英語。

非常感謝!

+1

您已經實現了你的視圖模型INotifyPropertyChanged接口?......表現出一定的代碼,如果你能... – 2014-12-04 08:35:51

回答

1

使用例如ObservableCollection(OC)司機是正確的做法。此外使用CollectionViewSource(CVS)也是一個好方法。在你的情況下產生的問題是,當源(OC)發生變化時,你的CVS纔會被實現。這意味着如果驅動程序被添加或刪除。

當您的源對象的屬性(如「BestLap」)更改時,您需要通知您。

在stackoverflow和其他網站處理這個問題有幾個問題/答案。

我們可能的解決方案(從第二鏈路中提取):啓用 「IsLiveSortingRequested」 並添加一個 「SortDescription」 含有被用於排序的特性。

 <Window.Resources> 
      <CollectionViewSource x:Key="cvsDrivers" Source="{Binding DriversList}" IsLiveSortingRequested="True"> 
       <CollectionViewSource.LiveSortingProperties> 
        <clr:String>BestLap</clr:String> 
       </CollectionViewSource.LiveSortingProperties> 
       <CollectionViewSource.SortDescriptions> 
        <scm:SortDescription PropertyName="BestLap" /> 
       </CollectionViewSource.SortDescriptions> 
      </CollectionViewSource> 
     </Window.Resources> 

編輯:

這裏是使用適當的方法MVVM一個(非常簡單和基本的)工作實施例:

模型(driver.cs):

public class Driver : INotifyPropertyChanged 
{ 
    private string name; 
    public string Name 
    { 
     get { return name; } 
     set 
     { 
      name = value; 
      OnPropertyChanged("Name"); 
     } 
    } 

    private double bestLap; 
    public double BestLap 
    { 
     get { return bestLap; } 
     set 
     { 
      bestLap = value; 
      OnPropertyChanged("BestLap"); 
     } 
    } 

    private int startNr; 
    public int StartNr 
    { 
     get { return startNr; } 
     set 
     { 
      startNr = value; 
      OnPropertyChanged("StartNr"); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

ViewModel.cs:

public class DriverViewModel 
{ 
    public ObservableCollection<Driver> DriverList { get; set; } 

    public DriverViewModel() 
    { 
     DriverList = new ObservableCollection<Driver>(); 
    } 
} 

的視圖(MainWindow.xaml):

<Window.Resources> 
    <CollectionViewSource x:Key="CvsDriver" 
          Source="{Binding DriverList}" 
          IsLiveSortingRequested="True"> 
     <CollectionViewSource.SortDescriptions> 
      <componentModel:SortDescription PropertyName="BestLap" Direction="Ascending" /> 
     </CollectionViewSource.SortDescriptions> 
    </CollectionViewSource> 

    <Style x:Key="DriverListBoxItemContainerStyle" TargetType="{x:Type ListBoxItem}"> 
     <Setter Property="Background" Value="Transparent"/> 
     <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="Padding" Value="2,0,0,0"/> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="{x:Type ListBoxItem}"> 
        <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true"> 
         <StackPanel Height="Auto" Orientation="Horizontal"> 
          <TextBlock TextWrapping="Wrap" Text="{Binding BestLap, StringFormat=\{0:F2\}}"/> 
          <TextBlock TextWrapping="Wrap" Text="{Binding StartNr}" Margin="8,0,0,0"/> 
          <TextBlock TextWrapping="Wrap" Text="{Binding Name}" Margin="8,0,0,0"/> 
         </StackPanel> 
        </Border> 
        <ControlTemplate.Triggers> 
         <Trigger Property="IsSelected" Value="true"> 
          <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/> 
          <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/> 
         </Trigger> 
         <MultiTrigger> 
          <MultiTrigger.Conditions> 
           <Condition Property="IsSelected" Value="true"/> 
           <Condition Property="Selector.IsSelectionActive" Value="false"/> 
          </MultiTrigger.Conditions> 
          <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/> 
          <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/> 
         </MultiTrigger> 
         <Trigger Property="IsEnabled" Value="false"> 
          <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> 
         </Trigger> 
        </ControlTemplate.Triggers> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
    </Style> 
</Window.Resources> 

<Grid> 
    <ListBox ItemsSource="{Binding Source={StaticResource CvsDriver}}" 
      ItemContainerStyle="{DynamicResource DriverListBoxItemContainerStyle}" /> 
</Grid> 

最後的主窗口。CS

public partial class MainWindow : Window 
{ 
    private readonly DriverViewModel driverViewModel; 

    public MainWindow() 
    { 
     // Timer generating random BestLap double values from 1.0 to 4.0 every 5 seconds 
     DispatcherTimer randomlyUpdateDriverBestLapTimer = new DispatcherTimer(); 
     randomlyUpdateDriverBestLapTimer.Interval = TimeSpan.FromSeconds(5); 
     randomlyUpdateDriverBestLapTimer.Tick += RandomlyUpdateDriverBestLapTimerOnTick; 

     driverViewModel = new DriverViewModel(); 

     Driver driver = new Driver { BestLap = 1.2, Name = "Meyer", StartNr = 1 }; 
     driverViewModel.DriverList.Add(driver); 

     driver = new Driver { BestLap = 1.4, Name = "Sand", StartNr = 2 }; 
     driverViewModel.DriverList.Add(driver); 

     driver = new Driver { BestLap = 1.5, Name = "Huntelaar", StartNr = 3 }; 
     driverViewModel.DriverList.Add(driver); 

     this.DataContext = driverViewModel; 

     InitializeComponent(); 

     randomlyUpdateDriverBestLapTimer.Start(); 
    } 

    private void RandomlyUpdateDriverBestLapTimerOnTick(object sender, EventArgs eventArgs) 
    { 
     // Important to declare Random object not in the loop because it will generate the same random double for each driver 
     Random random = new Random(); 

     foreach (var driver in driverViewModel.DriverList) 
     { 
      // Random double from 1.0 - 4.0 (Source code from https://stackoverflow.com/questions/1064901/random-number-between-2-double-numbers) 
      driver.BestLap = random.NextDouble() * (4.0 - 1.0) + 1.0; 
     } 
    } 
+0

那正是我想要的。但我不知道什麼是「CollectionViewSource.LiveSortingProperties> BestLap 」用於。沒有這些線,一切正常。 – Ferran 2014-12-04 09:26:58

+0

非常感謝你@SSchutte完美的作品。 – Ferran 2014-12-05 08:34:17