2016-09-02 41 views
1

注:改寫爲MCVE二傳手不是始終要求在DataTrigger

我已經制定了類似這樣的,其目的是爲了隱藏ListView如果它是空的,或者顯示它並選擇第一個項目,如果它不是空的UI

<Window x:Class="BrokenSelection.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:BrokenSelection" 
     mc:Ignorable="d" 
     SizeToContent="WidthAndHeight" 
     Title="MainWindow"> 
    <Window.DataContext> 
     <local:ViewModel/> 
    </Window.DataContext> 
    <StackPanel> 
     <ListView x:Name="MyListView" ItemsSource="{Binding Items}"> 
      <ListView.Style> 
       <Style TargetType="ListView"> 
        <Setter Property="Visibility" Value="Collapsed"/> 
        <Style.Triggers> 
         <DataTrigger Binding="{Binding HasItems, RelativeSource={RelativeSource Self}}" Value="True"> 
          <Setter Property="Visibility" Value="Visible"/> 
          <Setter Property="SelectedIndex" Value="0"/> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </ListView.Style> 
     </ListView> 
     <Button Content="Set" Click="Button_Set"/> 
     <Button Content="Clear" Click="Button_Clear"/> 
     <Button Content="Step" Click="Button_Step"/> 
    </StackPanel> 
</Window> 

我有一個虛擬機來實現這樣的

class ViewModel : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    private List<string> items = new List<string>(); 
    public List<string> Items 
    { 
     get 
     { 
      return items; 
     } 

     set 
     { 
      items = value; 
      PropertyChanged?.DynamicInvoke(this, new PropertyChangedEventArgs("Items")); 
     } 
    } 
} 

我有代碼隱藏這樣

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void Button_Set(object sender, RoutedEventArgs e) 
    { 
     var l = new List<string>(); 
     l.Add("Item1"); 
     l.Add("Item2"); 
     l.Add("Item3"); 
     l.Add("Item4"); 
     l.Add("Item5"); 

     var vm = DataContext as ViewModel; 
     vm.Items = l; 
    } 

    private void Button_Clear(object sender, RoutedEventArgs e) 
    { 
     var vm = DataContext as ViewModel; 
     vm.Items = new List<string>(); 
    } 

    private void Button_Step(object sender, RoutedEventArgs e) 
    { 
     MyListView.SelectedIndex++; 
    } 
} 

我的問題是SetterSelectedIndex成功,只要我點擊「設置」,「清」,「設置」,「清晰」等......

但是,如果我點擊「設置」 ,「步驟」,「清除」,「設置」,SelectedIndex在第二個「集合」上結束爲-1而不是0。其他Setter會在列表消失並正確重新顯示時執行。爲什麼在我的觸發器中手動更改SelectedIndex會中斷setter?

+0

嗯,我不知道。抱歉。你的問題有了很大的改進。謝謝你。我可以很容易地重現你描述的行爲。我注意到,選擇的改變並不重要,如果我甚至只是點擊列表視圖,就會中斷後續的觸發分配。我所知道的:一般來說,顯式賦值屬性會覆蓋樣式賦值(包括觸發器)。 _可能_這就是這裏發生的事情。但即使向視圖模型添加索引屬性並以這種方式間接設置列表視圖選擇索引也無法解決此問題。 –

+0

我沒有時間更努力尋找解決方法。在你上面的例子中,你直接操作'SelectedIndex'屬性,所以我想一種選擇是在代碼隱藏的其他地方做這個。似乎有一些關於列表視圖對象的事情,一旦某些外部力量改變了屬性,觸發器就不會再這樣做了。但是我不清楚具體情況以解釋爲什麼或者解決觸發器設置問題。 –

回答

0

它適用於我。請參閱我下面Minimal, Complete, and Verifiable code example

class ViewModel : INotifyPropertyChanged 
{ 
    private bool _hasItems; 

    public bool HasItems 
    { 
     get { return _hasItems; } 
     set { _UpdateValue(ref _hasItems, value); } 
    } 

    public ObservableCollection<string> Items { get; } = new ObservableCollection<string>(); 

    public event PropertyChangedEventHandler PropertyChanged; 

    private void _UpdateValue<T>(ref T field, T newValue, [CallerMemberName] string propertyName = null) 
    { 
     if (!object.Equals(field, newValue)) 
     { 
      field = newValue; 
      PropertyChanged?.DynamicInvoke(this, new PropertyChangedEventArgs(propertyName)); 

      if (propertyName == nameof(HasItems)) 
      { 
       if (HasItems) 
       { 
        Items.Add("test item"); 
       } 
       else 
       { 
        Items.Clear(); 
       } 
      } 
     } 
    } 
} 
<Window x:Class="TestSO39298712SelectedIndexSetter.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:l="clr-namespace:TestSO39298712SelectedIndexSetter" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.DataContext> 
    <l:ViewModel/> 
    </Window.DataContext> 

    <StackPanel> 
    <CheckBox IsChecked="{Binding HasItems}" Content="HasItems"/> 
    <TextBlock Text="{Binding SelectedIndex, ElementName=listBox1, StringFormat=SelectedIndex: {0}}"/> 
    <ListView x:Name="listBox1" ItemsSource="{Binding Items}"> 
     <ListView.Style> 
     <p:Style TargetType="ListView"> 
      <Setter Property="Visibility" Value="Collapsed"/> 
      <p:Style.Triggers> 
      <DataTrigger Binding="{Binding HasItems, RelativeSource={RelativeSource Self}}" Value="True"> 
       <Setter Property="Visibility" Value="Visible"/> 
       <Setter Property="SelectedIndex" Value="0"/> 
      </DataTrigger> 
      </p:Style.Triggers> 
     </p:Style> 
     </ListView.Style> 
    </ListView> 
    </StackPanel> 
</Window> 

我複製你提供直入這個例子的代碼。我所做的只是添加了足夠的其他代碼,以便我有一個工作示例,可以證明SelectedIndex屬性是否確實發生了變化。

你可以查看上面的內容,看看你是否能找到你的代碼有什麼不同。如果您仍然無法弄清楚自己犯了什麼錯誤,請修正您的問題,使其包含上述的良好MCVE,但可以可靠地重現問題。

+0

我不打電話添加和清除。我正在重置實際的收集實例 – cppguy

+0

您還向您的虛擬機添加了'HasItems'。我在ListView本身上使用'HasItems'。 – cppguy

+0

@cppguy:我虛擬機中的'HasItems'與觸發器無關。就像我說的那樣,包括觸發器在內的風格只是來自帖子的直接複製/粘貼。無論如何,這裏的重點是展示一個可行的版本。我認爲你的理由是不同的;如果一個工作示例不足以幫助您修復代碼,則需要修復您的問題,使其包含一個好的[mcve]。它仍然沒有。 –

0

提前給彼得的回答,他每次收集變化時都沒有指定新的ObservableCollection實例,他只是增加/刪除它的項目,這可能使他的例子工作(通常這是正確的方式使用ObservableCollection ,對集合本身進行更改,而不是實例化新集合並分配它)。

從您在問題中提供的內容中,我懷疑您在SelectedIndex屬性中看到的-1值是由分配空ObservableCollection引起的。正如你所說:

在屬性的每一項任務之間的1個 或多個項目的一個新的集合,我第一次給它分配一個空的集合(NOT NULL)

我不是100除非你會像Peter提到的那樣在一個好的MCVE中提供你的代碼,否則肯定會有我的答案。

+0

我不會在可觀察集合上調用'Add',因爲有時我必須添加數百個項目,而且我擔心UI會收到數百個通知來更新 – cppguy

+0

我明白。當您將SearchedResults屬性分配兩次(第一次使用空集合,然後使用全集)時,SelectedIndex會更改一次還是兩次?你可以通過調用ListView的SelectionChanged事件來檢查它。 –

+0

對空集合的分配將其設置爲-1。我添加了一個EDIT2部分,上面可以添加更多顏色的情況 – cppguy

0

修訂

我可以重現的問題,如果我加載收集,滾動,清楚,然後再加載,觸發不設置SelectedIndex

MainWindow.xaml

<Window x:Class="WpfApplication2.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:WpfApplication2" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="300" Width="525"> 
    <DockPanel> 
     <StackPanel DockPanel.Dock="Top" Orientation="Vertical"> 
      <Button Click="Load_Button_Click">Load</Button> 
      <Button Click="Clear_Button_Click">Clear</Button> 
      <Button Click="Scroll_Button_Click">Scroll</Button> 
     </StackPanel> 
     <ListView DockPanel.Dock="Bottom" Name="SearchResultListView" ItemsSource="{Binding}"> 
      <ListView.View> 
       <GridView> 
        <GridViewColumn Header="Name" Width="60" DisplayMemberBinding="{Binding Name}" /> 
        <GridViewColumn Header="Age" Width="60" DisplayMemberBinding="{Binding Age}" /> 
       <GridViewColumn Header="Email" Width="140" DisplayMemberBinding="{Binding Email}" /> 
       </GridView> 
      </ListView.View> 
      <ListView.Style> 
       <Style TargetType="ListView"> 
        <Setter Property="Visibility" Value="Collapsed"/> 
        <Style.Triggers> 
         <DataTrigger Binding="{Binding HasItems, RelativeSource={RelativeSource Self}}" Value="True"> 
          <Setter Property="Visibility" Value="Visible"/> 
          <Setter Property="SelectedIndex" Value="0"/> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </ListView.Style> 
     </ListView> 
    </DockPanel> 
</Window> 

MainWindow.xaml.cs

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    public class User 
    { 
     public string Name { get; set; } 
     public int Age { get; set; } 
     public string Email { get; set; } 
    } 

    private void Clear_Button_Click(object sender, RoutedEventArgs e) 
    { 
     ObservableCollection<User> items = new ObservableCollection<User>(); 
     SearchResultListView.ItemsSource = items; 
    } 

    private void Load_Button_Click(object sender, RoutedEventArgs e) 
    { 
     ObservableCollection<User> items = new ObservableCollection<User>(); 

     items.Add(new User() { Name = "Smith", Age = 18, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Joe", Age = 19, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Walter", Age = 17, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Tim1", Age = 44, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Tim2", Age = 44, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Tim3", Age = 44, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Tim4", Age = 44, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Tim5", Age = 44, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Tim6", Age = 44, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Tim7", Age = 44, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Tim8", Age = 44, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Tim9", Age = 44, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Tim10", Age = 44, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Tim11", Age = 44, Email = "[email protected]" }); 
     items.Add(new User() { Name = "Tim12", Age = 44, Email = "[email protected]" }); 

     SearchResultListView.ItemsSource = items; 
    } 

    private void Scroll_Button_Click(object sender, RoutedEventArgs e) 
    { 
     if (SearchResultListView.SelectedIndex < this.SearchResultListView.Items.Count - 1) 
     { 
      SearchResultListView.SelectedIndex++; 
      SearchResultListView.ScrollIntoView(this.SearchResultListView.SelectedItem); 
     } 
     else 
     { 
      SearchResultListView.SelectedIndex = 0; 
      SearchResultListView.ScrollIntoView(this.SearchResultListView.SelectedItem); 
     } 
    } 
} 
+0

看看我的EDIT2部分。這可能是導致此問題的原因,但仍然不清楚原因。 – cppguy

0

我終於發現了這個奇怪問題的解決方案。如果設置IsSynchronizedWithCurrentItem="True",則選擇不會神祕地設回-1。