Problem with binding

Hey guys, im having issues with binding in this code: https://paste.mod.gg/bxttdnuopcri/4 i started doing my game from the start to make it easier to code later
BlazeBin - bxttdnuopcri
A tool for sharing your source code with the world!
55 Replies
Mąż Zuzanny Harmider Szczęście
i ment from scratch
FusedQyou
FusedQyou3w ago
What's the issue? Side note, maybe look at the CommunityToolkit. It will make the whole process of implementing INotifyPropertyChanged incredibly easy as it will generate everything for you.
Mąż Zuzanny Harmider Szczęście
I tried but the issue is:
public class Tile : Image{ //cannot make it also inherit from ObservableObject
}
public class Tile : Image{ //cannot make it also inherit from ObservableObject
}
basically:
System.Windows.Data Error: 40 : BindingExpression path error: 'Left' property not found on 'object' ''ViewModel' (HashCode=30265903)'. BindingExpression:Path=Left; DataItem='ViewModel' (HashCode=30265903); target element is 'Tile' (Name=''); target property is 'Left' (type 'Double')
System.Windows.Data Error: 40 : BindingExpression path error: 'Left' property not found on 'object' ''ViewModel' (HashCode=30265903)'. BindingExpression:Path=Left; DataItem='ViewModel' (HashCode=30265903); target element is 'Tile' (Name=''); target property is 'Left' (type 'Double')
@FusedQyou ?
FusedQyou
FusedQyou3w ago
This seems more like an issue with the xaml rather than the code behind of it Can you share that?
Mąż Zuzanny Harmider Szczęście
it is shared inside the link i sent u
<Window x:Class="TileGame.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:TileGame"
mc:Ignorable="d"
ResizeMode="NoResize"
WindowState="Maximized"
Icon="tile_0106.png"
Title="MainWindow" Height="1080" Width="1920">
<ItemsControl ItemsSource="{Binding Tiles}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="Image">
<Setter Property="Canvas.Left" Value="{Binding Path=Left}"/>
<Setter Property="Canvas.Top" Value="{Binding Path=Top}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path=Source}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
<Window x:Class="TileGame.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:TileGame"
mc:Ignorable="d"
ResizeMode="NoResize"
WindowState="Maximized"
Icon="tile_0106.png"
Title="MainWindow" Height="1080" Width="1920">
<ItemsControl ItemsSource="{Binding Tiles}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="Image">
<Setter Property="Canvas.Left" Value="{Binding Path=Left}"/>
<Setter Property="Canvas.Top" Value="{Binding Path=Top}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path=Source}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Window>
like it works for the first tile added and then stops @Foosed
FusedQyou
FusedQyou3w ago
The ViewModel class should have Left and Top in a Tiles collection. It goes wrong here because one, or more, of these things don't exist Idk what ViewModel is though Also, this code is very confusing. Why did you implement INotifyPropertyChanged on the Window? The whole pattern should exist inside the view mode. The code behind should be practically empty but it almost seems like you have it all in there instead of the ViewModel By default, Bindings assume it has to fetch and act on the view model. That's the purpose of MVVM. You can modify this behaviour to point to a difference source, as it's incredibly configurable. However, you should move this logic to the view model since that's the best practice.
Mąż Zuzanny Harmider Szczęście
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TileGame;
namespace TileGame.ViewModels
{
public class ViewModel
{
public ObservableCollection<Tile> Tiles { get; private set; }
public ViewModel() {
Tiles= new ObservableCollection<Tile>();
}
}
}
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TileGame;
namespace TileGame.ViewModels
{
public class ViewModel
{
public ObservableCollection<Tile> Tiles { get; private set; }
public ViewModel() {
Tiles= new ObservableCollection<Tile>();
}
}
}
inotifychanged on mainwindow is for the score, ure right tho, i can move it to viewmodel
FusedQyou
FusedQyou3w ago
Maybe do that first and worry about the error later What is Image here btw? Why not put it on the Image level then? It is common that you make a class specific with INPC if you use them in a view. For example, depsite a Vector3 being a struct, people often make a class version with INCP and just convert them back and forth Sounds dumb until you realize the whole system has a lot of extra bells attached
Mąż Zuzanny Harmider Szczęście
its for it to display image
//MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using TileGame.ViewModels;
namespace TileGame
{
/// <summary>
/// Logika interakcji dla klasy MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public ViewModel ViewModel { get; private set; }

public MainWindow()
{
InitializeComponent();
ViewModel = new ViewModel();
DataContext = ViewModel;
}
}
}
//MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using TileGame.ViewModels;
namespace TileGame
{
/// <summary>
/// Logika interakcji dla klasy MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public ViewModel ViewModel { get; private set; }

public MainWindow()
{
InitializeComponent();
ViewModel = new ViewModel();
DataContext = ViewModel;
}
}
}
//ViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using TileGame;
namespace TileGame.ViewModels
{
public class ViewModel : INotifyPropertyChanged
{
private int _score;
public event PropertyChangedEventHandler PropertyChanged;
public static Dictionary<TileType, BitmapImage> TileImages { get; private set; }
public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public int Score
{
get { return _score; }
set
{
if (_score != value)
{
_score = value;
OnPropertyChanged();
}
}
}
public ObservableCollection<Tile> Tiles { get; private set; }
public ViewModel() {
TileImages = Enum.GetValues(typeof(TileType)).Cast<TileType>().ToDictionary(type => type, type => new BitmapImage(new Uri(Tile.GetImagePath(type), UriKind.RelativeOrAbsolute)));
Tiles = new ObservableCollection<Tile>
{
new Tile((MainWindow)Application.Current.MainWindow, TileType.GrassA, 0, 0),
new Tile((MainWindow)Application.Current.MainWindow, TileType.GrassB, Tile.Size, 0),
new Tile((MainWindow)Application.Current.MainWindow, TileType.GrassC, Tile.Size*2, 0),
};
}
}
}
//ViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using TileGame;
namespace TileGame.ViewModels
{
public class ViewModel : INotifyPropertyChanged
{
private int _score;
public event PropertyChangedEventHandler PropertyChanged;
public static Dictionary<TileType, BitmapImage> TileImages { get; private set; }
public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public int Score
{
get { return _score; }
set
{
if (_score != value)
{
_score = value;
OnPropertyChanged();
}
}
}
public ObservableCollection<Tile> Tiles { get; private set; }
public ViewModel() {
TileImages = Enum.GetValues(typeof(TileType)).Cast<TileType>().ToDictionary(type => type, type => new BitmapImage(new Uri(Tile.GetImagePath(type), UriKind.RelativeOrAbsolute)));
Tiles = new ObservableCollection<Tile>
{
new Tile((MainWindow)Application.Current.MainWindow, TileType.GrassA, 0, 0),
new Tile((MainWindow)Application.Current.MainWindow, TileType.GrassB, Tile.Size, 0),
new Tile((MainWindow)Application.Current.MainWindow, TileType.GrassC, Tile.Size*2, 0),
};
}
}
}
new code it does, Tile has property Left and Top dont understand this
FusedQyou
FusedQyou3w ago
If it's not yours forget it Alternatively you can wrap the image in INPC using a wrapper that just mimics it but it also depends on if it helps anything I think having it on the Tile level is fine enough, assuming you implemented it there Does the new code have the same issue?
Mąż Zuzanny Harmider Szczęście
when i launch the app it looks like this
No description
Mąż Zuzanny Harmider Szczęście
the first one is placed and then it is having issues idk why
FusedQyou
FusedQyou3w ago
I'm not sure. Has the xaml changed at all?
Mąż Zuzanny Harmider Szczęście
nope i tried to add tile before it, but it did nothing
FusedQyou
FusedQyou3w ago
Can you share the Tile class?
Mąż Zuzanny Harmider Szczęście
public class Tile : Image,INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private MainWindow MainWindow;
public TileType Type;
public static int Size { get; set; } = 32;
private double _top { get; set; }
public double Top
{
get { return _top; }
set
{
if (_top != value)
{
_top = value;
OnPropertyChanged(nameof(Top));
}
}
}
private double _left { get; set; }
public double Left {
get { return _left; }
set
{
if (_left != value)
{
_left = value;
OnPropertyChanged(nameof(Left));
}
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
Debug.WriteLine($"Property changed: {propertyName}");
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public Tile()
{

}
public Tile(MainWindow window,TileType type, double top, double left)
{
Type = type;
Top = top;
Left = left;
MainWindow = window;
Width = Size;
Height = Size;
if (ViewModel.TileImages != null)
{
Source = ViewModel.TileImages[Type];
}
else
{
Source = new BitmapImage(new Uri(GetImagePath(type),UriKind.RelativeOrAbsolute));
}

}
public class Tile : Image,INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private MainWindow MainWindow;
public TileType Type;
public static int Size { get; set; } = 32;
private double _top { get; set; }
public double Top
{
get { return _top; }
set
{
if (_top != value)
{
_top = value;
OnPropertyChanged(nameof(Top));
}
}
}
private double _left { get; set; }
public double Left {
get { return _left; }
set
{
if (_left != value)
{
_left = value;
OnPropertyChanged(nameof(Left));
}
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
Debug.WriteLine($"Property changed: {propertyName}");
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public Tile()
{

}
public Tile(MainWindow window,TileType type, double top, double left)
{
Type = type;
Top = top;
Left = left;
MainWindow = window;
Width = Size;
Height = Size;
if (ViewModel.TileImages != null)
{
Source = ViewModel.TileImages[Type];
}
else
{
Source = new BitmapImage(new Uri(GetImagePath(type),UriKind.RelativeOrAbsolute));
}

}
@Foosed
FusedQyou
FusedQyou3w ago
Okay. No clue. What happends if you remove the ItemsControl.ItemTemplate part? See if removing parts of the code fixes it. I assume that would be the one that "fixes" it
Mąż Zuzanny Harmider Szczęście
this seems off
No description
FusedQyou
FusedQyou3w ago
idk what that says missing datacontext?
Mąż Zuzanny Harmider Szczęście
Didnt find DataContext for element "Tiles" yeah but how should it be DataContext=ViewModel.Tiles?
Mąż Zuzanny Harmider Szczęście
like wtf do u mean Left doesnt exist
No description
Mąż Zuzanny Harmider Szczęście
public ViewModel() {
TileImages = Enum.GetValues(typeof(TileType)).Cast<TileType>().ToDictionary(type => type, type => new BitmapImage(new Uri(Tile.GetImagePath(type), UriKind.RelativeOrAbsolute)));
Tiles = new ObservableCollection<Tile>
{
new Tile((MainWindow)Application.Current.MainWindow, TileType.GrassA, 0, 0),
new Tile((MainWindow)Application.Current.MainWindow, TileType.GrassB, Tile.Size, 0),
new Tile((MainWindow)Application.Current.MainWindow, TileType.GrassC, Tile.Size*2, 0),
};
foreach(Tile tile in Tiles)
{
Debug.WriteLine(tile.Left + " "+tile.Top);
}
}
public ViewModel() {
TileImages = Enum.GetValues(typeof(TileType)).Cast<TileType>().ToDictionary(type => type, type => new BitmapImage(new Uri(Tile.GetImagePath(type), UriKind.RelativeOrAbsolute)));
Tiles = new ObservableCollection<Tile>
{
new Tile((MainWindow)Application.Current.MainWindow, TileType.GrassA, 0, 0),
new Tile((MainWindow)Application.Current.MainWindow, TileType.GrassB, Tile.Size, 0),
new Tile((MainWindow)Application.Current.MainWindow, TileType.GrassC, Tile.Size*2, 0),
};
foreach(Tile tile in Tiles)
{
Debug.WriteLine(tile.Left + " "+tile.Top);
}
}
0 0
0 32
0 64
0 0
0 32
0 64
like it is there...
Nasdack
Nasdack3w ago
what is this? so your bindable properties are in your code behind and you have a ViewModel declared?
Nasdack
Nasdack3w ago
this is not the MVVM pattern
Mąż Zuzanny Harmider Szczęście
ik idk how to do it
Nasdack
Nasdack3w ago
GitHub
wpfui/samples/Wpf.Ui.Demo.Mvvm at main · lepoco/wpfui
WPF UI provides the Fluent experience in your known and loved WPF framework. Intuitive design, themes, navigation and new immersive controls. All natively and effortlessly. - lepoco/wpfui
Nasdack
Nasdack3w ago
Here's a sample of how to set up MVVM properly And use the MVVM toolkit or ReactiveUI
Mąż Zuzanny Harmider Szczęście
mvvm is a option tho
Nasdack
Nasdack3w ago
The former is preferred if you don't need advanced functionality
Mąż Zuzanny Harmider Szczęście
im so lost...
Nasdack
Nasdack3w ago
Put a pause on your current work Download that sample Launch it, play around with it, and see how it works
Mąż Zuzanny Harmider Szczęście
how to download it?
Nasdack
Nasdack3w ago
for this particular sample it is available as a template which can be obtained from a VS extension
Nasdack
Nasdack3w ago
WPF UI - Visual Studio Marketplace
Extension for Visual Studio - WPF UI provides the Fluent experience in your known and loved WPF framework. Intuitive design, themes, navigation and new immersive controls. All natively and effortlessly.
Mąż Zuzanny Harmider Szczęście
wdym as a template
Nasdack
Nasdack3w ago
Download the extension and restart VS
Nasdack
Nasdack3w ago
Then create a new project and select this template
No description
Mąż Zuzanny Harmider Szczęście
done what vs version do u have?
Nasdack
Nasdack3w ago
VS 22 but it shouldn't matter Did you not wait for the extension to be installed? Load up a project and go check if it was installed
Mąż Zuzanny Harmider Szczęście
i have that extension installed alreadt
Nasdack
Nasdack3w ago
Double check
Mąż Zuzanny Harmider Szczęście
installing it again ig
Nasdack
Nasdack3w ago
Also you need to search for it in the search bar
Mąż Zuzanny Harmider Szczęście
ok, worked after reinstall I dont understand 80% of the stuff in the example
Nasdack
Nasdack3w ago
that is the underlaying issue you need to learn how to apply the pattern properly before you can begin to use it play around with this template see what connects what, then apply what you've learnt to your original project
Nasdack
Nasdack3w ago
Befoe you do that however, give this a read https://learn.microsoft.com/en-us/dotnet/architecture/maui/mvvm
Model-View-ViewModel - .NET
Overview of the Model-View-ViewModel pattern used by .NET MAUI
Nasdack
Nasdack3w ago
I can't find an article specific for WPF but this one should explain the concept as well
Mąż Zuzanny Harmider Szczęście
ok, learned to add pages i give up...
XAML Llama
XAML Llama3w ago
You're conflating your data and your UI layers. This is a good talk that talks about how to separate those by construction so you're not blending your UI and data layers: https://www.youtube.com/watch?v=83UVWrfYreU
dotnet
YouTube
MVVM Building Blocks for WinUI and WPF Development
Embark with us on a hands-on journey to acquire the foundational elements of modern Windows app development. We'll show you how XAML, Data Binding, and MVVM come together to empower your development process, increase agility, and simplify your codebase! You'll end up with the essential skills to start crafting applications with WinUI or WPF and...
XAML Llama
XAML Llama3w ago
Controls in your UI layer should use DependencyProperties instead to accept bindings in XAML to your underlying VMs/models which are the things which implement INotifyPropertyChanged. There's a new DependencyProperty generator which can help in Windows Community Toolkit Labs, as it is a lot of boilerplate.

Did you find this page helpful?