Ошибки ComboBox WPF с привязкой данных - PullRequest
0 голосов
/ 17 октября 2019

Я новичок в C # и продолжаю получать ошибки, ниже которых я не могу удалить.

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=HorizontalContentAlignment; DataItem=null; target element is 'RibbonGalleryItem' (Name=''); target property is 'HorizontalContentAlignment' (type 'HorizontalAlignment')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=VerticalContentAlignment; DataItem=null; target element is 'RibbonGalleryItem' (Name=''); target property is 'VerticalContentAlignment' (type 'VerticalAlignment')

Мой код приведен ниже, и я не могу точно сказать, какая строка вызывает ошибку, ноЯ подозреваю, что это связано с RibbonRadioButtons, так как, если я удаляю их, я не получаю ошибок. Ошибки появляются только после нажатия двух или более переключателей. Ответ на ComboBoxItem продолжает выдавать ошибку привязки, несмотря на то, что стиль предположил, что причиной было несколько операторов Refresh (), но я не могу понять, как этого избежать.

Может кто-нибудь помочь мне разрешитьэтот вопрос?

XAML

<Grid>
  <DockPanel>
    <r:Ribbon DockPanel.Dock="Top" x:Name="Ribbon" SelectedIndex="0">
      <r:RibbonGroup Header="Continent" Width="Auto">
        <r:RibbonComboBox x:Name="CountryList" Height="Auto" VerticalAlignment="Center" HorizontalContentAlignment="Left">
          <r:RibbonGallery x:Name="cbSelectedCountry" SelectedValue="{Binding SelectedCountry, Mode=TwoWay}" SelectedValuePath="DisplayName" >
            <r:RibbonGalleryCategory x:Name="cbCountryList" ItemsSource="{Binding CountryView}" DisplayMemberPath="DisplayName" />
          </r:RibbonGallery>
        </r:RibbonComboBox>
        <WrapPanel>
          <r:RibbonRadioButton x:Name="All" Label="All" GroupName="ContinentGroup"
                    Height="Auto" Width="Auto" HorizontalAlignment="Left"
                    IsChecked="{Binding Path=All}">
          </r:RibbonRadioButton>
          <r:RibbonRadioButton x:Name="Africa" Label="Africa" GroupName="ContinentGroup"
                    Height="Auto" Width="Auto" HorizontalAlignment="Left"
                    IsChecked="{Binding Path=Africa}">
          </r:RibbonRadioButton>
          <r:RibbonRadioButton x:Name="America" Label="America" GroupName="ContinentGroup"
                    Height="Auto" Width="Auto" HorizontalAlignment="Left"
                    IsChecked="{Binding Path=America}">
          </r:RibbonRadioButton>
        </WrapPanel>
      </r:RibbonGroup>
    </r:Ribbon>
  </DockPanel>
</Grid>

C #

public class MySettings : INotifyPropertyChanged
{
    private readonly ObservableCollection<Country> countries;
    private ContinentViewModel selectedContinent;
    private static string selectedCountry;
    private int selectedRadioGroup;
    private ObservableCollection<ContinentViewModel> continents;
    private ListCollectionView countryView;
    public event PropertyChangedEventHandler PropertyChanged;
    private bool _All;
    private bool _Africa;
    private bool _America;

    public MySettings()
    {
        countries = new ObservableCollection<Country>(
            new[]
            {
                new Country() { Continent = Continent.Africa, DisplayName = "Algeria" },
                new Country() { Continent = Continent.Africa, DisplayName = "Egypt" },
                new Country() { Continent = Continent.Africa, DisplayName = "Chad" },
                new Country() { Continent = Continent.Africa, DisplayName = "Ghana" },
                new Country() { Continent = Continent.America, DisplayName = "Canada" },
                new Country() { Continent = Continent.America, DisplayName = "Greenland" },
                new Country() { Continent = Continent.America, DisplayName = "Haiti" }
            });
        CountryView = (ListCollectionView)CollectionViewSource.GetDefaultView(countries);
        CountryView.Filter += CountryFilter;
        Continents = new ObservableCollection<ContinentViewModel>(Enum.GetValues(typeof(Continent)).Cast<Continent>().Select(c => new ContinentViewModel { Model = c }));
    }

    public bool All
    {
        get => _All;
        set
        {
            _All = value;
            CountryView.Refresh();
            SelectedCountry = _All ? countries.FirstOrDefault().DisplayName : SelectedCountry;
            OnPropertyChanged("All");
        }
    }

    public bool Africa
    {
        get => _Africa;
        set
        {
            _Africa = value;
            CountryView.Refresh();
            SelectedCountry = _Africa ? countries.Where(_ => _.Continent == Continent.Africa).FirstOrDefault().DisplayName : SelectedCountry;
            OnPropertyChanged("Africa");
        }
    }

    public bool America
    {
        get => _America;
        set
        {
            _America = value;
            CountryView.Refresh();
            SelectedCountry = _America ? countries.Where(_ => _.Continent == Continent.America).FirstOrDefault().DisplayName : SelectedCountry;
            OnPropertyChanged("America");
        }
    }

    private bool CountryFilter(object obj)
    {
        var country = obj as Country;
        if (country == null) return false;
        if (All && !Africa && !America) return true;
        else if (!All && Africa && !America) return country.Continent == Continent.Africa;
        else if (!All && !Africa && America) return country.Continent == Continent.America;
        return true;
    }

    public ObservableCollection<ContinentViewModel> Continents
    {
        get => continents;
        set
        {
            continents = value;
            OnPropertyChanged("Continents");
        }
    }

    public ListCollectionView CountryView
    {
        get => countryView;
        set
        {
            countryView = value;
            OnPropertyChanged("CountryView");
        }
    }

    public class Country
    {
        public string DisplayName { get; set; }
        public Continent Continent { get; set; }
    }

    public enum Continent
    {
        All,
        Africa,
        America
    }

    public class ContinentViewModel
    {
        public Continent Model { get; set; }
        public string DisplayName => Enum.GetName(typeof(Continent), Model);
    }

    public ContinentViewModel SelectedContinent
    {
        get => selectedContinent;
        set
        {
            selectedContinent = value;
            OnContinentChanged();
            this.OnPropertyChanged("SelectedContinent");
        }
    }

    private void OnContinentChanged()
    {
        CountryView.Refresh();
    }

    public int SelectedRadioGroup
    {
        get => selectedRadioGroup;
        set
        {
            selectedRadioGroup = value;
            OnPropertyChanged("SelectedRadioGroup");
        }
    }

    public string SelectedCountry
    {
        get => selectedCountry;
        set
        {
            if (selectedCountry == value) return;
            selectedCountry = value;
            OnPropertyChanged("SelectedCountry");
        }
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

1 Ответ

0 голосов
/ 17 октября 2019

Я использовал mvvmlight и внес некоторые изменения, чтобы упростить ваш код:

<Window x:Class="WpfTest.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:WpfTest"
    DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <DockPanel>
        <Ribbon DockPanel.Dock="Top" x:Name="Ribbon" SelectedIndex="0">
            <RibbonGroup Header="Continent" Width="Auto">
                <RibbonComboBox x:Name="CountryList" Height="Auto" VerticalAlignment="Center" HorizontalContentAlignment="Left">
                    <RibbonGallery x:Name="cbSelectedCountry" SelectedItem="{Binding SelectedCountry, Mode=TwoWay}">
                        <RibbonGalleryCategory x:Name="cbCountryList" ItemsSource="{Binding CountryView}" DisplayMemberPath="DisplayName" />
                    </RibbonGallery>
                </RibbonComboBox>
                <WrapPanel>
                    <RibbonRadioButton x:Name="All" Label="All" GroupName="ContinentGroup" Height="Auto" Width="Auto" HorizontalAlignment="Left" IsChecked="{Binding Path=All}"></RibbonRadioButton>
                    <RibbonRadioButton x:Name="Africa" Label="Africa" GroupName="ContinentGroup" Height="Auto" Width="Auto" HorizontalAlignment="Left" IsChecked="{Binding Path=Africa}"></RibbonRadioButton>
                    <RibbonRadioButton x:Name="America" Label="America" GroupName="ContinentGroup" Height="Auto" Width="Auto" HorizontalAlignment="Left" IsChecked="{Binding Path=America}"></RibbonRadioButton>
                </WrapPanel>
            </RibbonGroup>
        </Ribbon>
    </DockPanel>
</Grid>

Я создал свойство SelectedCountry типа Country, чтобы связать его со списком, вместо того, чтобы задавать строку вродеваш код делал.

using GalaSoft.MvvmLight;
using System.Collections.ObjectModel;
using System.Windows.Data;

namespace WpfTest.ViewModel
{
/// <summary>
/// This class contains properties that the main View can data bind to.
/// <para>
/// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
/// </para>
/// <para>
/// You can also use Blend to data bind with the tool's support.
/// </para>
/// <para>
/// See http://www.galasoft.ch/mvvm
/// </para>
/// </summary>
public class MainViewModel : ViewModelBase
{
    private readonly ObservableCollection<Country> countries;
    private ListCollectionView _countryView;

    public ListCollectionView CountryView
    {
        get { return _countryView; }
        set { this.Set(ref _countryView, value); }
    }

    private Country _SelectedCountry;
    public Country SelectedCountry
    {
        get { return _SelectedCountry; }
        set { this.Set(ref _SelectedCountry, value); }
    }

    private bool _All;
    public bool All
    {
        get { return _All; }
        set
        {
            this.Set(ref _All, value);
            CountryView.Refresh();
        }
    }

    private bool _Africa;
    public bool Africa
    {
        get { return _Africa; }
        set
        {
            this.Set(ref _Africa, value);
            if (SelectedCountry != null && SelectedCountry.Continent != Continent.Africa)
            {
                SelectedCountry = null;
            }
            CountryView.Refresh();
        }
    }

    private bool _America;
    public bool America
    {
        get { return _America; }
        set
        {
            this.Set(ref _America, value);
            if (SelectedCountry != null && SelectedCountry.Continent != Continent.America)
            {
                SelectedCountry = null;
            }
            CountryView.Refresh();
        }
    }


    /// <summary>
    /// Initializes a new instance of the MainViewModel class.
    /// </summary>
    public MainViewModel()
    {
        countries = new ObservableCollection<Country>(
        new[]
        {
            new Country() { Continent = Continent.Africa, DisplayName = "Algeria" },
            new Country() { Continent = Continent.Africa, DisplayName = "Egypt" },
            new Country() { Continent = Continent.Africa, DisplayName = "Chad" },
            new Country() { Continent = Continent.Africa, DisplayName = "Ghana" },
            new Country() { Continent = Continent.America, DisplayName = "Canada" },
            new Country() { Continent = Continent.America, DisplayName = "Greenland" },
            new Country() { Continent = Continent.America, DisplayName = "Haiti" }
        });
        CountryView = (ListCollectionView)CollectionViewSource.GetDefaultView(countries);
        CountryView.Filter += CountryFilter;
        CountryView.Refresh();


        ////if (IsInDesignMode)
        ////{
        ////    // Code runs in Blend --> create design time data.
        ////}
        ////else
        ////{
        ////    // Code runs "for real"
        ////}
    }

    private bool CountryFilter(object obj)
    {
        if (obj is Country c)
        {
            if (Africa && c.Continent != Continent.Africa)
            {
                return false;
            }
            if (America && c.Continent != Continent.America)
            {
                return false;
            }
        }

        return true;
    }
}

public enum Continent
{
    All,
    Africa,
    America
}

public class Country
{
    public string DisplayName { get; set; }
    public Continent Continent { get; set; }
}
}

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

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

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