Ошибка привязки ItemsControl - PullRequest
0 голосов
/ 07 мая 2018

У меня есть Canvas внутри ItemsControl, у которого ItemsSource есть ObservableCollection. При этом это Rectangle, свойство Width которого привязано к свойству wWdith RectangleOverlay. Ширина отображается 0 независимо от того, что я пробовал, и я пытался перемещать вещи вокруг. Вот вид.

<Grid>
        <Label  HorizontalAlignment="Center" 
                Content="IMAGE FROM CAMERA" 
                Width="Auto" FontFamily="White"
                Canvas.Left="50" Panel.ZIndex="2"/>
        <ItemsControl Panel.ZIndex="3" 
                   ItemsSource="{Binding Source=MyProperty}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Canvas Height="Auto" >
                    <Rectangle Width="{Binding Path=wWidth,
                                       UpdateSourceTrigger=PropertyChanged}"
                           Height="50"
                           Canvas.Left="50"
                           Canvas.Top="50"                                   
                           Stroke="Red"
                           StrokeThickness="2"/>
                    <TextBox Canvas.Left="50"
                         Canvas.Top="100"
                         Text="TEXT"/>
                </Canvas>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>

</Grid>

А вот код для класса RectangleOverlay

public class RectOverlay : Shape, INotifyPropertyChanged
{
    public RectOverlay()
    {

    }

   //I DONT KNOW WHAT EXACTLY NEEDS TO BE IN HERE 
    protected override Geometry DefiningGeometry
    {
        get { return new RectangleGeometry();}
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }

    private double _width;
    public double wWidth
    {
        get { return _width; }
        set
        {
            _width = value;
            OnPropertyChanged("wWidth");
        }
    }


}

А вот большая часть кода (MainWindow.xaml.cs).

 public partial class MainWindow : Window, INotifyPropertyChanged
{

    private ObservableCollection<RectOverlay> ListShapes;


    public MainWindow()
    {
        InitializeComponent();

        this.DataContext = this;

        MyProperty = new ObservableCollection<RectOverlay>();

        ListShapes.Add(new RectOverlay() { wWidth = 100 });

        _timer = new Timer(2000); // Set up the timer for 3 seconds
        _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
        _timer.Enabled = true; // Enable it
    }

    public ObservableCollection<RectOverlay> MyProperty
    {
        get { return ListShapes; }
        set
        {
            ListShapes = value;
            OnPropertyChanged("MyProperty");
        }
    }


}

Я не могу понять, почему привязка не срабатывает.

System.Windows.Data Error: 40 : BindingExpression path error: 'wWidth' property not found on 'object' ''Char' (HashCode=5046349)'. BindingExpression:Path=wWidth; DataItem='Char' (HashCode=5046349); target element is 'Rectangle' (Name=''); target property is 'Width' (type 'Double')

Я читал и пытался выяснить из других подобных постов на SO о том, как вывести эту ошибку. Я думаю, что поток привязки установлен правильно. Контекст данных всего окна - это код позади, после ItemsControl Source - ObservableCollection пользовательского класса (RectangleOverlay). & внутри шаблона данных я задаю путь к свойству моего пользовательского класса.

1 Ответ

0 голосов
/ 07 мая 2018

Первая ошибка в том, что вы написали

ItemsSource="{Binding Source=MyProperty}"

вместо

ItemsSource="{Binding Path=MyProperty}"

или просто

ItemsSource="{Binding MyProperty}"

Установка объекта Source привязок на MyProperty просто присваивает строковый литерал "MyProperty", который является IEnumerable из Chars и, следовательно, интерпретируется как таковой.

Привязка в ItemTemplate неизбежно жалуется, что не может найти свойство wWidth для объекта типа Char.


Но есть еще одна проблема, с которой вы сталкиваетесь. Вот правильный ответ, и, честно говоря, мне пришлось копать, чтобы получить это для вас ... У меня никогда не было этой проблемы раньше.

Во-первых, поскольку вы используете пользовательскую фигуру, ItemsControl игнорирует пользовательский DataTemplate и пытается нарисовать RectOverlay, который вы указали.

Теперь, конечно, вы этого не видите, потому что вы устанавливаете только wWidth, что не является реальной шириной рисования. Вам необходимо установить Width, Height, Stroke, StrokeThickness и т. Д. В соответствии с вашей пользовательской формой, а затем вам необходимо полностью удалить DataTemplate из вашего XAML.

Однако, как только вы это сделаете, вы все равно заметите, что он не тянет. Это потому, что ваш DefiningGeometry возвращает пробел RectangleGeometry. Это должны быть пути и т. Д., Которые вы собираетесь рисовать. (Подробнее об этом позже).

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

Еще одна вещь, которую стоит отметить ... Если вы используете произвольную фигуру, она относится к типу DependencyObject. Это означает, что реализация INotifyPropertyChanged излишня. Вместо этого вы можете использовать пользовательский DependencyProperty.

Поэтому, пожалуйста, просмотрите этот код ниже. Я изменил RectOverlay, чтобы он был больше похож на ViewModel, и я обновил MyProperty в MainWindow, чтобы он стал DependencyProperty.

Вот код MainWindow, стоящий за

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;
        MyProperty.Add(new RectOverlay() { wWidth = 100 });
    }

    public ObservableCollection<RectOverlay> MyProperty
    {
        get { return (ObservableCollection<RectOverlay>)GetValue(MyPropertyProperty); }
        set { SetValue(MyPropertyProperty, value); }
    }

    public static readonly DependencyProperty MyPropertyProperty =
        DependencyProperty.Register(nameof(MyProperty), typeof(ObservableCollection<RectOverlay>), typeof(MainWindow), new PropertyMetadata(new ObservableCollection<RectOverlay>()));
}

Вот модель представления RectOverlay

public class RectOverlay : INotifyPropertyChanged
{
    private double wwidth;
    public double wWidth
    {
        get { return wwidth; }
        set
        {
            wwidth = value;
            OnPropertyChanged(nameof(wWidth));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged([CallerMemberName] string propertyName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

Я оставил XAML таким, каким он был у вас (за исключением удаления Source =)

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

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

...