Member 12938297 Ответов: 1

Как привязать несколько значений флажков к одному текстовому полю с помощью методов MVVM WPF?


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

Что я уже пробовал:

В виду :
<Window x:Class="multichkboxsel.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:multichkboxsel"

        xmlns:viewmodel="clr-namespace:multichkboxsel.ViewModel"

        xmlns:converter="clr-namespace:multichkboxsel.converter"

        xmlns:view="clr-namespace:multichkboxsel.View"

        mc:Ignorable="d"

        Title="MainWindow" Height="350" Width="525">
       
        <Window.Resources>
        <viewmodel:chkviewmdl x:Key="vm"></viewmodel:chkviewmdl>
        <converter:myconverter x:Key="cv"></converter:myconverter>
        </Window.Resources>
        <StackPanel Orientation="Vertical" Margin="20" DataContext="{Binding Source={StaticResource vm}}">
            <CheckBox Width="120" Name="cbIndia" Content="India" Command="{Binding MyCommand}">
                <CheckBox.CommandParameter>
                    <MultiBinding Converter="{StaticResource cv}">
                        <Binding ElementName="cbIndia" Path="Content"/>
                        <Binding ElementName="cbIndia" Path="IsChecked"/>
                    </MultiBinding>
                </CheckBox.CommandParameter>
            </CheckBox>
            <CheckBox Width="120" Name="cbUS" Content="US" Command="{Binding MyCommand}">
                <CheckBox.CommandParameter>
                    <MultiBinding Converter="{StaticResource cv}">
                        <Binding ElementName="cbUS" Path="Content"/>
                        <Binding ElementName="cbUS" Path="IsChecked"/>
                    </MultiBinding>
                </CheckBox.CommandParameter>
            </CheckBox>
            <CheckBox Width="120" Name="cbUK" Content="UK" Command="{Binding MyCommand}">
                <CheckBox.CommandParameter>
                    <MultiBinding Converter="{StaticResource cv}">
                        <Binding ElementName="cbUK" Path="Content"/>
                        <Binding ElementName="cbUK" Path="IsChecked"/>
                    </MultiBinding>
                </CheckBox.CommandParameter>
            </CheckBox>
            <CheckBox Width="120" Name="cbChina" Content="China" Command="{Binding MyCommand}">
                <CheckBox.CommandParameter>
                    <MultiBinding Converter="{StaticResource cv}">
                        <Binding ElementName="cbChina" Path="Content"/>
                        <Binding ElementName="cbChina" Path="IsChecked"/>
                    </MultiBinding>
                </CheckBox.CommandParameter>
            </CheckBox>
            <TextBox Width="300" Margin="20" Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
        </StackPanel>
    </Window>  

В модель представления:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace multichkboxsel.ViewModel
{
    class chkviewmdl : INotifyPropertyChanged
    {

        private ObservableCollection<string> _countries;
        public ObservableCollection<string> Countries
        {
            get { return _countries; ; }
            set
            {
                _countries = value;
                OnPropertyChange("Countries");
            }
        }
        public ICommand MyCommand { get; set; }
        public chkviewmdl()
        {
            MyCommand = new RelayCommand(executemethod, canexecutemethod);
        }

        private string _name;
        public string Name
        {
            get { return _name; }
            set
            {
                _name = value;
                OnPropertyChange("Name");
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChange(string propertyname)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyname));
            }
        }

        private bool canexecutemethod(object parameter)
        {
            return true;
        }

        private void executemethod(object parameter)
        {
            //Name = (string)parameter;
            var values = (object[])parameter;
        
            string name = (string)values[0];
            bool check = (bool)values[1];
            if (check)
            {
                Countries.Add(name);
            }
            else
            {
                Countries.Remove(name);
            }

            Name = "";
            foreach (string item in Countries)
            {
                Name = Name + item;
            }

        }

    }
}

И Я ТОЖЕ ИСПОЛЬЗОВАЛ КЛАСС КОНВЕРТЕРА...

Graeme_Grant

Похоже, что ошибка находится в классе конвертера (код недоступен). Установите точку останова в классе преобразователя и пройдите через код...

1 Ответов

Рейтинг:
12

Graeme_Grant

Ты делаешь много работы для себя. Вам нужно упростить свой код. Вот вам пример:

1. Во-первых, sperate INotifyPropertyChanged в многоразовый базовый класс:

public abstract class ObservableBase : INotifyPropertyChanged
{
    public void Set<TValue>(ref TValue field, TValue newValue,
                            [CallerMemberName] string propertyName = "")
    {
        if (EqualityComparer<TValue>.Default.Equals(field, default(TValue))
            || !field.Equals(newValue))
        {
            field = newValue;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

2. Далее, давайте инкапсулируем страну ueach в ее собственную модель:
public class CountryModel : ObservableBase
{
    private bool isChecked;
    public bool IsChecked
    {
        get { return isChecked; }
        set { Set(ref isChecked, value); }
    }

    private string name;
    public string Name
    {
        get { return name; }
        set { Set(ref name, value); }
    }
}

3. Теперь давайте включим коллекцию стран в нашу модель представления:
public class MainViewModel : ObservableBase
{
    public ObservableCollection<CountryModel> Countries { get; set; } = new ObservableCollection<CountryModel>
    {
        new CountryModel { Name = "India", IsChecked = true },
        new CountryModel { Name = "US" },
        new CountryModel { Name = "UK" },
        new CountryModel { Name = "China" }
    };
}

4. Наконец, пришло время сделать пользовательский интерфейс: показать пользователю список выбранных стран. Я также добавил список выбранных стран, который отражает изменения, внесенные пользователем:

4а. Страницы XAML:
<Window

    x:Class="MultiSelectCheckList.MainWindow"

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"



    mc:Ignorable="d"

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"



    xmlns:clr="clr-namespace:System;assembly=mscorlib"

    xmlns:local="clr-namespace:MultiSelectCheckList"



    Title="CodeProject - MultiSelect CheckboxList"

    Height="350" Width="525" WindowStartupLocation="CenterScreen">

    <Window.DataContext>
        <local:MainViewModel/>
    </Window.DataContext>

    <Window.Resources>

        <CollectionViewSource x:Key="SelectedCountries" Source="{Binding Countries}"

                              IsLiveFilteringRequested="True"

                              Filter="CollectionViewSource_Filter">
            <CollectionViewSource.LiveFilteringProperties>
                <clr:String>IsChecked</clr:String>
            </CollectionViewSource.LiveFilteringProperties>
        </CollectionViewSource>

    </Window.Resources>

    <Grid Margin="20">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <ItemsControl x:Name="Selection" ItemsSource="{Binding Countries}"

                      BorderThickness="1" BorderBrush="Silver">
            <ItemsControl.Resources>
                <DataTemplate DataType="{x:Type local:CountryModel}">
                    <CheckBox Content="{Binding Name}"

                              IsChecked="{Binding IsChecked, Mode=TwoWay}"

                              Margin="10"/>
                </DataTemplate>
            </ItemsControl.Resources>
        </ItemsControl>

        <ListBox Grid.Column="1" Margin="10 0 0 0"

                 ItemsSource="{Binding Source={StaticResource SelectedCountries}}">
            <ListBox.Resources>
                <DataTemplate DataType="{x:Type local:CountryModel}">
                    <TextBlock Text="{Binding Name}" Margin="10"/>
                </DataTemplate>
            </ListBox.Resources>
        </ListBox>
    </Grid>

</Window>

4Б. Код для фильтра класса collectionviewsource :
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void CollectionViewSource_Filter(object sender, FilterEventArgs e)
    {
        e.Accepted = (e.Item as CountryModel).IsChecked;
    }
}

Теперь список стран легко расширяется без каких-либо изменений в коде XAML.


Member 12938297

Спасибо..