Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / WPF, Silverlight Новый топик    Ответить
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
 Привязка координат элемента в Canvas  [new]
111DarkFox111
Member

Откуда:
Сообщений: 8
Здравствуйте, я недавно начал изучать WPF и столкнулся с проблемой. Я пытался привязать(забиндить) координаты элемента, который находится в Canvas:

<Canvas Name="Canvas">
    <Rectangle Fill="Black" Width="60" Height="60" Canvas.Left="{Binding X, Mode=OneWay}" Canvas.Top="{Binding Y, Mode=OneWay}"/>
</Canvas>


namespace WpfApp7
{
    public partial class MainWindow : Window
    {
        public double X { get; set; }
        public double Y { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            X = 111;
            Y = 111;
        }
    }
}


Однако это не возымело никакого эффекта. При этом, если менять свойства Canvas.Top и Canvas.Left вручную, то квадрат меняет своё расположение в редакторе. Я пробовал ставить Mode TwoWay и даже использовать интерфейс INotifyPropertyChanged, который применяется в патерне MVVM, но ничего из этого не помогло. У меня складывается такое ощущения, что если это заработает-свершится настоящее чудо. Скажите, пожалуйста, что я делаю не так.
3 ноя 18, 19:28    [21723368]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 3305
Canvas.Left="{Binding X, Mode=OneWay}" Canvas.Top="{Binding Y, Mode=OneWay}"
неправильный Binding, Вы делайте связывание с контекстом, а не с окном. В контексте нет полей X и Y
Они есть в классе окна. Либо используйте ElementName связывание и задайте имя окну, либо используйте RelativeSource связывание
3 ноя 18, 19:47    [21723380]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 3305
<Canvas Name="Canvas">
    <Rectangle Fill="Black" Width="60" Height="60" 
               Canvas.Left="{Binding X, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" 
               Canvas.Top="{Binding Y, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}"/>
</Canvas>

вот рабочий вариант вашего примера
3 ноя 18, 19:50    [21723382]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
111DarkFox111
Member

Откуда:
Сообщений: 8
Спасибо за быстрый ответ.
3 ноя 18, 20:28    [21723401]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
111DarkFox111
Member

Откуда:
Сообщений: 8
Хотя нет, знаете что? Спасибо вам ОГРОМНОЕ. На других сайтах люди даже особо не смотрели на мой код и отмахивались этим шаблонным: нужен интерфейс INotifyPropertyChanged и тому подобное. А вы действительно мне помогли. Буду почаще заходить на этот сайт)
3 ноя 18, 20:54    [21723414]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Eld Hasp
Member

Откуда:
Сообщений: 225
111DarkFox111
Хотя нет, знаете что? Спасибо вам ОГРОМНОЕ. На других сайтах люди даже особо не смотрели на мой код и отмахивались этим шаблонным: нужен интерфейс INotifyPropertyChanged и тому подобное. А вы действительно мне помогли. Буду почаще заходить на этот сайт)
Вы задали вопрос http://www.cyberforum.ru/wpf-silverlight/thread2345072.html#post13027693
И я Вам там ответил. В том числе дал полностью рабочий пример кода. Интерфейс INotifyPropertyChanged для свойств предназначенных для привязывания обязателен.
Вот тот пример кода
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
 
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
 
        private double  _x;
        private double  _y;
 
        public double X { get=>_x; set {_x=value; OnPropertyChanged("X");} }
        public double Y { get=>_y; set{_y=value; OnPropertyChanged("Y");}}
 
        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
 
            X = 111;
            Y = 111;
        }
    }
4 ноя 18, 00:31    [21723469]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Eld Hasp
Member

Откуда:
Сообщений: 225
Roman Mejtes
<Canvas Name="Canvas">
    <Rectangle Fill="Black" Width="60" Height="60" 
               Canvas.Left="{Binding X, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" 
               Canvas.Top="{Binding Y, Mode=OneWay, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}"/>
</Canvas>

вот рабочий вариант вашего примера
Roman Mejtes проясните, пожалуйста. А то я чего-то недопонял.
Биндинги Вы исправили. Но в самом окне эти свойства реализованы без INotifyPropertyChanged. Установка значений идёт уже после инициализации элементов окна.
А каким образом тогда элемент узнаЁт об изменении значения свойства?
Или интерфейс INotifyPropertyChanged не всегда нужен?
4 ноя 18, 00:41    [21723472]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20286
А он и не узнаёт.
Роман исправил только привязку. А если хочешь, чтобы изменение свойства отслеживалось - делай нотификацию. Но тут может проще даже сделать DependencyProperty - нет смысла добавлять к DependencyObject (коим является Window) еще и INotifyPropertyChanged
4 ноя 18, 01:03    [21723476]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20286
Eld Hasp
Установка значений идёт уже после инициализации элементов окна.
Не скажу со 100% уверенностью, но вроде бы привязки будут обработаны уже после отработки конструктора, поэтому начальная значения привязка все равно увидит.

В любом случае, считывание свойств привязкой идет в потоке пользовательского интерфейса, даже если я меняю их (и издаю нотификацию) в другом потоке. Так что, думаю, что вышесказанное сработает (проверять лень ))
4 ноя 18, 01:06    [21723477]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Eld Hasp
Member

Откуда:
Сообщений: 225
Shocker.Pro
Eld Hasp
Установка значений идёт уже после инициализации элементов окна.
Не скажу со 100% уверенностью, но вроде бы привязки будут обработаны уже после отработки конструктора, поэтому начальная значения привязка все равно увидит.

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

Результаты экспериментов.
Если устанавливать привязку через ElementName, то инициализацию свойства надо проводить, до InitializeComponent();. Если позже - без INPC - значения не изменяются.
Если устанавливать через DataContext (как в моём примере), то значения можно установить в любом месте конструктора окна. Если позже (допустим в Loaded) - то тоже без INPC изменения не замечаются.
4 ноя 18, 01:46    [21723480]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
111DarkFox111
Member

Откуда:
Сообщений: 8
Eld Hasp
Вы задали вопрос http://www.cyberforum.ru/wpf-silverlight/thread2345072.html#post13027693
И я Вам там ответил. В том числе дал полностью рабочий пример кода. Интерфейс INotifyPropertyChanged для свойств предназначенных для привязывания обязателен.
Вот тот пример кода
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
 
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged(string propertyName)
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
 
        private double  _x;
        private double  _y;
 
        public double X { get=>_x; set {_x=value; OnPropertyChanged("X");} }
        public double Y { get=>_y; set{_y=value; OnPropertyChanged("Y");}}
 
        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
 
            X = 111;
            Y = 111;
        }
    }


Да, теперь я вижу, что ваш вариант тоже работает и даже лучше. Простите мне мою невнимательность. Дело в том, что я сейчас пытаюсь написать небольшую игру и заодно изучить WPF(и патерн MVVM). Чтобы не кидать сюда весь мой неоптимизированный код на 500 строк я выделил лишь часть, но теперь понимаю, что выделил не то. При помощи ListBox мне было необходимо поместить в Canvas определённое количество элементов(допустим прямоугольников), которые должны быть расположены по всей плоскости Canvas так, будто они находятся в WrapPanel:

<ListBox Name="OutListBox" Background="Black" ItemsSource="{Binding OutputGameFields}" SelectedItem="{Binding OutputGameFieldSelected}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <Rectangle Width="60" Height="60" Fill="White" Canvas.Left="{Binding X, Mode=OneWay}" Canvas.Top="{Binding Y, Mode=OneWay}"/>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                        <ListBox.ItemsPanel>
                            <ItemsPanelTemplate>
                                <Canvas Background="Black" Width="600" Height="600"/>
                            </ItemsPanelTemplate>
                        </ListBox.ItemsPanel>
</ListBox>


public class MainViewModel : INotifyPropertyChanged
    {    
        private GameField outputGameFieldSelected;

        //Список, передаваемый в ListBox, таким образом на каждый объект класса GameField приходится один прямоугольник
        public ObservableCollection<GameField> OutputGameFields { get; set; } = new ObservableCollection<GameField>();
        public MainViewModel()
        {
          CreateGameField();
        }


        //Просто селектор, реализацию которого я вырезал
        public GameField OutputGameFieldSelected
        {
            get => outputGameFieldSelected;
            set
            {
                if (Equals(value, outputGameFieldSelected)) return;
                ItemBuilder(value);
            }
        }

        public void CreateGameField()
        {
            OutputGameFields.Clear();
            //Создание элементов и установка координат для каждого
            for (int i = 0; i < 10; i++)
            {
                for (int j = 0; j < 10; j++)
                {
                    OutputGameFields.Add(new GameField(){ X = j * 60, Y = i * 60 });
                }
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
}

public class GameField : INotifyPropertyChanged
    {
        private double x;
        private double y;

        //Поля, которые неправильно привязаны
        public double X
        {
            get => x;
            set
            {
                x = value;
                OnPropertyChanged();
            }
        }
        public double Y
        {
            get => y;
            set
            {
                y = value;
                OnPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }


К сожалению в данном случае проблема не в реализации интерфейса INotifyPropertyChanged, а в плохих биндингах. Не могли бы Вы помочь ещё раз, пожааалуйста?
4 ноя 18, 22:16    [21723822]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20286
111DarkFox111
При помощи ListBox мне было необходимо поместить в Canvas определённое количество элементов(допустим прямоугольников), которые должны быть расположены по всей плоскости Canvas так, будто они находятся в WrapPanel:
А зачем? Скажите листбоксу, чтобы использовал WrapPanel в качестве внутренней панели - и все.
А если функционала WrapPanel недостаточно, сделайте свою панель. Это проще, чем кажется, и сделает вас волшебником в своих глазах )
4 ноя 18, 22:20    [21723824]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20286
  <ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <ListBox.ItemsPanel>
      <ItemsPanelTemplate>
        <WrapPanel />
      </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <TextBlock Text="wwwwwwwww" />
    <TextBlock Text="wwwwwwwww" />
    <TextBlock Text="wwwwwwwww" />
    <TextBlock Text="wwwwwwwww" />
    <TextBlock Text="wwwwwwwww" />
    <TextBlock Text="wwwwwwwww" />
    <TextBlock Text="wwwwwwwww" />
    <TextBlock Text="wwwwwwwww" />
    <TextBlock Text="wwwwwwwww" />
  </ListBox>
4 ноя 18, 22:26    [21723827]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Eld Hasp
Member

Откуда:
Сообщений: 225
111DarkFox111
.......... При помощи ListBox мне было необходимо поместить в Canvas определённое количество элементов(допустим прямоугольников), которые должны быть расположены по всей плоскости Canvas так, будто они находятся в WrapPanel ..........
Честно говоря совершено не понял Вашей идеи. Если нужна WrapPanel почему тогда её и не использовать как написал Shocker.Pro ? Зачем из Canvas имитировать WrapPanel ?
4 ноя 18, 22:36    [21723830]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
111DarkFox111
Member

Откуда:
Сообщений: 8
Да я знаю про WrapPanel и использовал его до этого, но теперь мне нужны координаты, потому что я собираюсь перемещать элементы уже после добавления их в Canvas.
Создание своей собственной панели? Я не знал о такой возможности, но мне кажется что здесь она не поможет. Даже если я объединю функционал WrapPanel и Canvas мне всё равно будут нужны привязки координат элементов.
4 ноя 18, 22:40    [21723831]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Eld Hasp
Member

Откуда:
Сообщений: 225
111DarkFox111
Да я знаю про WrapPanel и использовал его до этого, но теперь мне нужны координаты, потому что я собираюсь перемещать элементы уже после добавления их в Canvas.
Создание своей собственной панели? Я не знал о такой возможности, но мне кажется что здесь она не поможет. Даже если я объединю функционал WrapPanel и Canvas мне всё равно будут нужны привязки координат элементов.
То есть, есть какой-то набор фигур. В списке есть уже правильно расставленные координаты. Надо только по этим координатам вывести эти фигуры.
Хотя в начале расстановка подобна WrapPanel, потом она меняется.
Я правильно понял?
4 ноя 18, 22:45    [21723834]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Roman Mejtes
Member

Откуда: г. Пермь
Сообщений: 3305
создайте свою панель и размещайте там элементы как вашей душе угодно
4 ноя 18, 22:53    [21723840]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
111DarkFox111
Member

Откуда:
Сообщений: 8
Сейчас объясню максимально подробно. Эти фигуры(прямоугольники), на самом деле являются игровым полем, по которому будет перемещаться игровой персонаж. У каждого такого прямоугольника есть свойства, определяющие является ли он обычной поверхностью или стеной. Собственно для обработки коллизии персонажа со стеной мне необходимы координаты. Да и для перемещения самого персонажа нужны его координаты. Правда как я буду добавлять персонажа на Canvas после всех фигур в патерне MVVM я ещё не придумал.
4 ноя 18, 22:54    [21723841]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20286
Например, панель может читать присоединяемые свойства своих детей как, к примеру, поступает Grid. В то же время эти свойства можно привязывать к модели представления.

То есть объявить координаты присоединяемыми свойствами и нацепить их на свои элементы
4 ноя 18, 22:55    [21723842]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Eld Hasp
Member

Откуда:
Сообщений: 225
111DarkFox111
Сейчас объясню максимально подробно. Эти фигуры(прямоугольники), на самом деле являются игровым полем, по которому будет перемещаться игровой персонаж. У каждого такого прямоугольника есть свойства, определяющие является ли он обычной поверхностью или стеной. Собственно для обработки коллизии персонажа со стеной мне необходимы координаты. Да и для перемещения самого персонажа нужны его координаты. Правда как я буду добавлять персонажа на Canvas после всех фигур в патерне MVVM я ещё не придумал.
Здесь я точно Вам не помощник. Я сам то ещё 4 месяцев нет как с WPF познакомился.
4 ноя 18, 23:08    [21723856]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
111DarkFox111
Member

Откуда:
Сообщений: 8
Shocker.Pro
Например, панель может читать присоединяемые свойства своих детей как, к примеру, поступает Grid. В то же время эти свойства можно привязывать к модели представления.

То есть объявить координаты присоединяемыми свойствами и нацепить их на свои элементы


Похоже, что самый простой способ для меня сейчас это всё же сделать через Grid и создать метод, который будет конвертировать значения X и Y в значения для Margin. В любом случае спасибо, что потратили время на вопросы такого неофита как я.

Можете ткнуть носом в материал о том как создавать свои панели?
4 ноя 18, 23:36    [21723869]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20286
https://professorweb.ru/my/WPF/Template/level18/18_11.php
https://professorweb.ru/my/WPF/Template/level18/18_12.php
4 ноя 18, 23:42    [21723877]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
111DarkFox111
Member

Откуда:
Сообщений: 8


К сообщению приложен файл. Размер - 57Kb
5 ноя 18, 00:03    [21723881]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Shocker.Pro
Member

Откуда: ->|<- :адуктО
Сообщений: 20286
Хм, для такого поля вообще подойдет обычный грид с набором фиксированных строк и столбцов, а координаты хранить в Grid.Column и Grid.Row
5 ноя 18, 00:06    [21723883]     Ответить | Цитировать Сообщить модератору
 Re: Привязка координат элемента в Canvas  [new]
Eld Hasp
Member

Откуда:
Сообщений: 225
Shocker.Pro
Хм, для такого поля вообще подойдет обычный грид с набором фиксированных строк и столбцов, а координаты хранить в Grid.Column и Grid.Row
Да, действительно так. Зачем выдумки с ListBox и Canvas?
Один Grid для фона, и сверху его накрыть другой панелью, можно Canvas, для персонажа.
5 ноя 18, 00:49    [21723888]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / WPF, Silverlight Ответить