Как сгруппировать флажки в древовидной структуре wpf mvvm, когда диапазон выбора равен [0,1] - PullRequest
2 голосов
/ 11 августа 2011

Я сделал дерево. Просмотр в wpf. С помощью MVVM.

все работает нормально, но есть одна проблема: конечный узел содержит несколько флажков, и у пользователя есть только два варианта: один или ни одного.

Tree View Sample Image

Так вот, как я могу ограничить пользователя, чтобы выбрать максимум один холодный напиток.

Я сделал один трюк, но это не сработало, когда я уже выбралнапиток, а затем я выбираю другое, кроме того, что я установил последнее выбранное значение в наблюдаемой коллекции как ложное, но это не влияет на представление, и выбранные флажки остаются установленными, хотя в коллекции верно только одно значение опции.

Я не могу использовать кнопку-переключатель вместо установленного флажка, потому что пользователь не может выбрать ни один из вариантов, и я не могу дать дополнительную опцию ни для одного из перечисленных выше вариантов.

Если у кого-то есть какое-либо решение, пожалуйста, дайте мне знатьочень благодарен.

обновленный вопрос: я думаю, что я не определил свою проблему должным образом, поэтому я даю свой фрагмент кодавот надеюсь, что благодаря этому я получу решение моей проблемы ...

Класс модели My View

namespace TestViewModels
{
 public class ViewModel :ViewModelBase

{

    private ObservableCollection<AvailableProducts> _MyTreeViewProperty

    public ObservableCollection<AvailableProducts> MyTreeViewProperty
    {
        get { return _MyTreeViewProperty
        set { _MyTreeViewProperty value; 
        RaisePropertyChanged("MyTreeViewProperty");}
    }

}

public class AvailableProducts

{

     private string _BrandName;

    public string BrandName
    {
        get { return _BrandName
        set { _BrandName = value; }
    }


    private bool _IsExpanded;
    public bool IsExpanded
    {
        get
        {
            return _IsExpanded;

        }
        set
        {
            _IsExpanded = value;

        }
    }

    private ObservableCollection<ProductTypes> _MyProductTypes

    public ObservableCollection<ProductTypes> MyProductTypes
    {
        get { return _MyProductTypes}
        set { _MyProductTypes= value; }
    }


}

public class ProductTypes
{
    private string _ProductTypeName;

    public string ProductTypeName
    {
        get { return _ProductTypeName;
        set { _ProductTypeNamevalue; }
    }



    private ObservableCollection<ProductSubTypes> _ProdSubTypes;

    public ObservableCollection<ProductSubTypes> ProdSubTypes
    {
        get { return _ProdSubTypes;}
        set { _ProdSubTypes;= value; }
    }


}


public class ProductSubTypes
{
    private string _ProductSubTypeName;

    public string ProductSubTypeName
    {
        get { return _ProductSubTypeName;
        set { _ProductSubTypeName;}
    }

    private int _ParentID;

    public int ParentID
    {
        get { return _ParentID;}
        set { _ParentID;= value; }
    }


    private bool _IsAssigned;

    public bool IsAssigned
    {
        get { return _IsAssigned; }
        set
        {
            _IsAssigned = value;

            if _ParentID;!= 0)
            {
               //updating data in database
               //Calling and setting new collection value in property

              //issue : updated collection sets in setter of MyTreeViewProperty but before calling getter
            // it comes to IsAssigned getter so view doesnt get updated  collection of MyTreeViewProperty 

            }
            RaisePropertyChanged("IsAssigned");
        }
    }


}

}

Просмотр

<Page x:Class="ShiftManagerViews.Pages.ProductTreeSelection
  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"  
  DataContext="{Binding ProductsTree, Source={StaticResource Locator}}"
  mc:Ignorable="d"  Width="870" Height="665"

>

     <TreeView  Margin="10,10,0,13" ItemsSource="{Binding MyTreeViewProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"  HorizontalAlignment="Left"

VerticalAlignment="Top" Width="800" Height="Auto" MinHeight="400" MaxHeight="800">
                <TreeView.ItemContainerStyle>

                    <Style TargetType="{x:Type TreeViewItem}">
                        <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
                     </Style>
                </TreeView.ItemContainerStyle>

                <TreeView.Resources>

                        <HierarchicalDataTemplate DataType="{x:Type local:AvailableProducts}"
                                      ItemsSource="{Binding MyProductTypes}"> 
                        <WrapPanel>
                            <Image Width="20" Height="20" Source="/ShiftManagerViews;component/Images/12.bmp"/>
                            <Label Content="{Binding BrandName}" FontSize="14"/>
                        </WrapPanel>
                    </HierarchicalDataTemplate>

                        <HierarchicalDataTemplate DataType="{x:Type local:ProductTypes}"
                                      ItemsSource="{Binding ProdSubTypes}">
                        <WrapPanel>
                            <Image Width="18" Height="15" Source="/ShiftManagerViews;component/Images/12.bmp"/>
                            <Label Content="{Binding ProductTypeName}" FontSize="13"/>
                        </WrapPanel>
                    </HierarchicalDataTemplate>
                        <!-- the template for showing the Leaf node's properties-->
                        <DataTemplate DataType="{x:Type local:ProductSubTypes}">
                            <StackPanel>

                                <CheckBox IsChecked="{Binding IsAssigned, Mode=TwoWay}" Content="{Binding ProductSubTypeName}" Height="25">

                            </CheckBox>
                            </StackPanel>
                        </DataTemplate>
                    </TreeView.Resources>
                </TreeView>

Ответы [ 5 ]

1 голос
/ 11 августа 2011

Как насчет использования ListBox для отображения подэлементов вместо TreeView? Вы можете сделать так, чтобы элементы содержали CheckBox для отображения IsSelected вместо выделения элемента.

0 голосов
/ 22 августа 2011

Наконец-то мне удалось решить мою проблему.

в свойстве Is Assigned я обновляю значения в моей базе данных и вызываю соответствующий метод с использованием обмена сообщениями MVVM Light и передаю в него в качестве параметра идентификатор родительского листа, выбранного в настоящий момент, ...

Добавлено свойствов классе Product Types, чтобы развернуть родительский узел последнего выбранного листа ..

В методе представления я обновляю источник контекста данных и передаю родительский идентификатор текущего выбранного листа листу в виртуальную машину, чтобы установить значение свойства Is Expanded в true...

Таким образом, моя точка зрения работает точно так же, как я хочу ... Если у кого-то есть решение, которое лучше этого, чем я буду рад узнать.

0 голосов
/ 17 августа 2011

Я сделал один трюк, но он не сработал, когда я уже выбрал напиток, а затем я выбрал другой, чем я установил последнее выбранное значение в наблюдаемой коллекции на false, но это не влияет наview и выбранные флажки остаются установленными, хотя в коллекции верно только одно значение параметра.

Убедитесь, что ваши дочерние объекты (AvailableProducts и SubProductTypes) также реализуют INotifyPropertyChanged, это будет гарантировать, что пользовательский интерфейс получит измененияпри изменении объекта.

Как только все ваши объекты обновят пользовательский интерфейс должным образом, вы сможете наложить и протестировать любую пользовательскую бизнес-логику, которая вам нужна.

Так что если у вас есть продукттип, который может иметь только один вложенный элемент, вы можете добавить свойство в ProductType с именем OnlyAllowOneChild.Всякий раз, когда дочерний объект вызывает измененное событие IsAssigned, родитель может установить false для всех остальных дочерних объектов.Это, конечно, требует от вас, чтобы родитель зарегистрировался в PropertyChangedEvent для детей или получил EventAggregator (MVVMLight Messenger или PRISM EvenAggregator) и создал систему обмена сообщениями.

0 голосов
/ 16 августа 2011

Я одобрил ответ Рэйчел, в WPF распространен способ связывания наборов радиокнопок или флажков. Если вы все еще хотите перейти к древовидной схеме, приведенный ниже код работает. Весь вид, связанный с кодом, находится в представлении, поэтому приведенный ниже код соответствует принципам MVVM. Если вы являетесь пуристом MVVM, вы можете оставить код позади и элемент управления TreeView в пользовательском элементе управления, если вы не хотите, чтобы какой-либо код был позади.

XAML:

<TreeView ItemsSource="{Binding Path=Drinks}">
    <TreeView.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding .}" Checked="OnCheckBoxChecked" Unchecked="OnCheckBoxUnchecked" Loaded="OnCheckBoxLoaded" />
        </DataTemplate>
    </TreeView.ItemTemplate>
</TreeView>

Код позади + VM:

public partial class Window1
{
    public Window1()
    {
        InitializeComponent();

        DataContext = new VM();
    }

    private void OnCheckBoxChecked(object sender, System.Windows.RoutedEventArgs e)
    {
        foreach (CheckBox checkBox in _checkBoxes.Where(cb => cb != sender))
        {
            checkBox.IsChecked = false;
        }

        (DataContext as VM).CurrentDrink = (sender as CheckBox).Content.ToString();
    }

    private void OnCheckBoxUnchecked(object sender, System.Windows.RoutedEventArgs e)
    {
        (DataContext as VM).CurrentDrink = null;
    }

    private void OnCheckBoxLoaded(object sender, System.Windows.RoutedEventArgs e)
    {
        _checkBoxes.Add(sender as CheckBox);
    }

    private List<CheckBox> _checkBoxes = new List<CheckBox>();
}

public class VM
{
    public List<string> Drinks
    {
        get
        {
            return new List<string>() { "Coffee", "Tea", "Juice" };
        }
    }

    public string CurrentDrink { get; set; }
}
0 голосов
/ 11 августа 2011

Я бы предположил, что ваш пользовательский интерфейс неправильный.Если пользователь может выбрать только один, то было бы лучше поменять их для переключателей и добавить опцию «Ни один из вышеперечисленных».Это даст вам поведение, которое вы хотите бесплатно, и ваш пользовательский интерфейс станет более интуитивным.

РЕДАКТИРОВАТЬ: Поскольку вы говорите, что не можете добавить опцию «Нет» и хотитеиспользуйте флажок (даже если я категорически не согласен с флажками, для которых более подходящим является переключатель - распространенная ошибка пользовательского интерфейса) ...

Техническая проблема, с которой вы, вероятно, сталкиваетесь, заключается в том, что ObservableCollection вызывает события уведомлений, только если Сама коллекция Изменения.т.е. только если элементы добавлены или удалены.Он не вызывает события, когда элементы в коллекции изменяются, поэтому изменение статуса флажка в коде не вызовет события, для которого будет действовать привязка пользовательского интерфейса.

Одно из решений этого - написать пользовательскийкласс, расширяющий ObservableCollection, обеспечивающий такое поведение

С MSDN :

Если вам необходимо узнать, изменил ли кто-либо свойство одного из элементов вколлекции, вам нужно убедиться, что элементы в коллекции реализуют интерфейс INotifyPropertyChanged, и вам необходимо вручную прикрепить обработчики событий, измененные свойством, для этих объектов.Независимо от того, как вы изменяете свойства объектов в коллекции, событие PropertyChanged коллекции не сработает.Фактически, обработчик события PropertyChanged ObservableCollection защищен - вы даже не можете реагировать на него, если не наследуете от класса и не выставляете его самостоятельно.Конечно, вы можете обработать событие PropertyChanged для каждого элемента в коллекции из вашей унаследованной коллекции

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...