WPF C# Two-Way Data Bind Not Working - c#

I recognize that this question is similar to others, but the others have not worked in my situation. I am trying to Two-Way Bind a textbox in my WPF to an XML file.
The data comes in perfectly into the textbox, but when I edit the textbox, the XML file is never changed. Based on what I have found online, my code seems like it should work. Here it is:
MainWindow.xaml
<Window x:Class="Learning_0._002.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Main Window"
WindowStartupLocation="CenterScreen"
Height="400" Width="950">
<Grid>
<Grid.Resources>
<XmlDataProvider x:Key="BusinessInfo" Source="BusinessData.xml" XPath="/Businesses/Business"/>
</Grid.Resources>
<Grid x:Name="BusinessInfo" DataContext="{StaticResource BusinessInfo}">
<TextBox Name="Name" Grid.Row="0" Grid.Column="1" Text="{Binding XPath=#Name,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Margin="106,93,717,250"/>
</Grid>
</Grid>
BusinessData.xml
<?xml version="1.0" encoding="utf-8" ?>
<Businesses>
<Business Name="Sample Company" Address="1234 East Road St. City, California 90068" Phone="555-555-5555" Fax="555-555-5556" Email="myemail#example.net" Website="www.example.com"/>
</Businesses>
I am new to this, and cannot find my error. Any corrections are appreciated!

Here's a question that is very similar to yours -
WPF two-way binding XML
It looks like what you need to do is instead of using a Grid.Resources you need use a datacontext instead. If you're going to be doing more advanced work I would recommend you use a class that contains all the data behind your UI elements. View this MSDN for more information - http://msdn.microsoft.com/en-us/library/ms743695(v=vs.110).aspx
<Grid.DataContext>
<XmlDataProvider x:Name="XMLData" Source="BusinessData.xml" XPath="/Businesses/Business"/>
</Grid.DataContext>
<Grid x:Name="BusinessInfo" Margin="98,49,118,144">
<TextBox Name="Name" Text="{Binding XPath=#Name, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" TextChanged="Name_TextChanged" />
</Grid>
And then in C# you will save it whenever they enter text into the textbox
private void Name_TextChanged(object sender, TextChangedEventArgs e)
{
XMLData.Document.Save("XMLFile1.xml");
}
You should know that when you save the file it will save to the same directory as where you run your executable. You can of course change where you save it to be the actual source of the XML.

Related

UI not updating using MVVM toolkit in WinUI 3

I am trying to change the size of a grid using data binding in order to be able to expand certain sections of my UI. I have looked online and nothing really seems to work. My window has a frame that loads a "root page" with another frame inside of it as seen in rootpage.xaml below. I have added a textbox but that does not seem to work. Interestingly enough, when I click the button present on the page. I do get a line outputted so my code is running. Adding a breakpoint shows similar results that the property FullScreenValue does in fact change. I think I am missing something in order to get the PropertyChanged event to be received or I may be unintentionally instancing multiple instances of my ViewModel. Looking for a solution.
My root page loaded into the frame in my window:
<Page
x:Class="MVVM.Views.rootPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MVVM.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:ViewModels="using:MVVM.ViewModels"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.DataContext>
<ViewModels:RootPageViewModel x:Name="ViewModel"/>
</Page.DataContext>
<Grid x:Name="frameGrid" ColumnDefinitions="*, *" RowDefinitions ="*, *" Grid.Row="1" Margin="15, 0, 15, 0" >
<Frame x:Name="topleftFrame" Grid.Column="0" Grid.Row="0" CornerRadius="8" Margin="10, 10, 10, 10" Grid.ColumnSpan="{Binding FullScreenValue,Mode=OneWay}" Grid.RowSpan="{Binding FullScreenValue, Mode=OneWay}"/>
<AppBarButton Icon="FullScreen" Grid.Column="0" Grid.Row="0" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="10,5,5,10" Command="{Binding FullScreenCommand, Mode=OneWay}"/>
Visibility="Visible"/>
<TextBlock Text="{Binding FullScreenValue, Mode=OneWay}" Grid.Row="1" Grid.Column="1"/>
</Grid>
</Page>
My ViewModel:
namespace MVVM.ViewModels
{
public partial class RootPageViewModel : ObservableObject
{
[ObservableProperty]
private int fullScreenValue;
public RootPageViewModel()
{
fullScreenValue = 1;
}
[ICommand]
void FullScreen()
{
fullScreenValue = 2;
Debug.WriteLine("HI");
}
}
}
As you can see I am trying to make use of the community toolkit. I have tried replacing some of these generated snippets with standard mvvm properties and commands to no avail. If I change the constructor to have a value of 2 I get my desired result, but can't seem to do it with this button! Send help.
My desired result is upon clicking the button, the frame will now span 2 columns and 2 rows instead of 1 column and 1 row. Maybe because this sort of UI concerns strictly the view it does not necessarily need a ViewModel but nonetheless I am still looking for help as I feel like I will run into this problem in the future. I am new to a lot of things in the Microsoft ecosystem so please forgive me if this is a repeat question and I just could not understand other answers.

Items doesn't show up after binding an XML file to a ListBox

I want to bind XML file to a ListBox. The problem is that items in ListBox doesn't show up after binding it to an XML file.
I've set ItemsSource in ListBox to StaticResource but it doesn't work, it doesn't show up in Visual Studio's Designer or in app itself.
Here's XAML code:
<Window x:Class="StudyNotes.ModifySubjectListWindow"
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:StudyNotes"
mc:Ignorable="d"
Title="" Height="150" Width="300" ResizeMode="NoResize">
<Grid>
<Grid.Resources>
<XmlDataProvider x:Key="SubjectData" Source="SubjectList.xml" XPath="/Subjects/Subject"/>
</Grid.Resources>
<DockPanel Margin="10">
<StackPanel DockPanel.Dock="Right" Margin="10,0,0,0">
<Button Name="AddSubjectButton" Margin="0,0,0,5">Add</Button>
<Button Name="DeleteSubjectButton">Delete</Button>
</StackPanel>
<ListBox x:Name="SubjectList" ItemsSource="{Binding Source={StaticResource SubjectData}, XPath=/Subjects/Subject}"></ListBox>
</DockPanel>
</Grid>
</Window>
Here's XML document:
<?xml version="1.0" encoding="utf-8" ?>
<Subjects>
<Subject Name="Subject1"/>
<Subject Name="Subject2"/>
<Subject Name="Subject3"/>
<Subject Name="Subject4"/>
</Subjects>
I expected this to be working and showing up, but there's definitely something wrong that I have no idea of.
There are a couple of items:
First of all, make sure that your 'SubjectList.xml' file has its Build Action property set to 'Content'.
Secondly, remove the 'XPath' stuff from the ItemsSource of your ListBox, that causes some trouble. You only need ItemsSource="{Binding Source={StaticResource SubjectData}}"
Thirdly, and this is the big one, your XML file is not set up quite right. After you make the two changes above, change your ListBox to a DataGrid for a quick test and it will highlight the trouble with the XML file:
It's kind of hard to see in this screenshot, but check out the 'Value' column. It's empty. Your XML file is set up where your data is stored in 'Attributes', specifically the 'Name' attribute, as you can see if you look over in the 'OuterXML' column. The XMlDataProvider grabs the Values in the XML file by default. You don't have any of those.
A better way to store your XML data might be:
<Subjects>
<Subject>Subject1</Subject>
<Subject>Subject2</Subject>
<Subject>Subject3</Subject>
<Subject>Subject4</Subject>
</Subjects>
If you do that, you get the expected result:

WPF right-click menu wouldn't use local language after changing Windows 10 regional settings

I've built a very basic WPF, but the context menus which appear when right-clicking on scrollbars or text selections remain in English, even when the local language/regional settings was changed to a different language. Code is attached at the bottom of this post.
At first, I thought maybe I didn't change all the language related settings on a system level, but when I try that in notepad, it works fine (meaning, the right-click menu isn't in English).
So I thought maybe it's some kind of a .net/WPF-specific issue, so I checked with Paint.net and it was fine there as well (though it might be non-WPF C# and C++ mixed?). Also tried to install the latest .net Framework Language Pack, which wouldn't install because it already exists on my PC.
You can see the differences in context menus between my app and Notepad in the following screenshots:
The code for the example app which reproduces this problem is pretty basic.
This is the xaml file:
<Window x:Class="WpfTestScrollLanguage.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:WpfTestScrollLanguage"
mc:Ignorable="d"
Loaded="Window_Loaded"
Language="uk-ua"
xml:lang="uk-UA"
Title="MainWindow" Height="100" Width="525">
<Grid Height="300" ScrollViewer.CanContentScroll="True" ScrollViewer.VerticalScrollBarVisibility="Visible" Language="uk-ua" xml:lang="uk-UA">
<ListView Language="uk-ua" xml:lang="uk-UA">
<Button Content="A" Height="20" Width="20"/>
<Button Content="B" Height="20" Width="20"/>
<Button Content="C" Height="20" Width="20"/>
<Button Content="D" Height="20" Width="20"/>
<TextBlock Height="300" Name="Text"/>
<TextBox Height="50" Width="300" Text="test123" Language="uk-ua" xml:lang="uk-UA"/>
</ListView>
</Grid>
and this is the .xaml.cs file that goes along with it (only the code that isn't auto-generated):
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var test = System.Globalization.CultureInfo.CurrentCulture;
var test2 = System.Globalization.CultureInfo.CurrentUICulture;
var test3 = this.Language;
var test4 = System.Windows.Markup.XmlLanguage.GetLanguage(System.Threading.Thread.CurrentThread.CurrentUICulture.Name);
Text.Text = "a\nb\nc\nd\ne\nf";
}
all of the test variables in runtime have shown "uk-UA" (as I've changed the OS language and region to Ukraine) even without setting those values manually within the xaml file itself. I just added them explicitly to the UI elements defined in the xaml file, to make sure I cover all possible cases.
edit: the app.config file is pretty simple, and doesn't seem related in this scenario:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
</startup>
</configuration>
Any idea about what I might be missing here? (Running on Windows 10 RS1, but I've observed the same problem also in RS2 and RS3-beta)
edit2: I've tried to find some existing apps that are based on WPF solely, and found WittyTwitter - there it seems that the text's context menu remains in English as well, but the whole app is English only so I can't really tell if maybe it's designed to be like that, or maybe it's really a WPF-based bug?
edit3: someone flagged this question as a dup of this one. Even though it might be more or less the same case, the answer there doesn't solve it (as I've described here), plus my question has more details to reproduce the problem.

Blend4, How to make WPF App(button show up pic)

How to make a button let a picture show up ?
what i Need to do, is creating 300 buttons each of these buttons will represent a unique path and pic every pic is defferent than the other? Unfortunately, WPF SketchFlow or Silverlight SketchFlow (I don't know the difference) can not be running as a program on computer. so what left is WFP app. Furthermore, i find it so difficult to just create one button linked to a pic's path!!!!.
I watched all of the Microsoft training Videos(the 5 days ones, if u dont know what i mean)http://www.microsoft.com/expression/resources/blendtraining/ . And still cant do it. I was searching for almost 4 weeks, and i still do.
Any idea how to create this essay app which require lots of work.
summery: 1-I don't know which app to use Silverlight or WPF app?(I don't know the difference)
2-i need to create a button that when i press on it, (New sorry) there will be a pic showing up in certain place that ill choose).
so in the end i need the code that will let the button work. direction for further info that ill need(websites that include vids or training by any type)
My regards SHeeDeED :)
Maybe you should start with a simple program: 1 button, showing 1 picture.
Handcraft it in XAML (no blend) and when you're stuck post a specific question here with the code.
I use Blend for most of my XAML/WPF UI design, and it works pretty well for me. I did, however, learn WPF and XAML by writing it longhand in the Visual Studio designer first. For any coding other than XAML (VB.NET, C#, C++, etc) I would highly suggest using Visual Studio as there are no bells and whistles in the Blend code window. It is essentially a colorful text editor.
As for buttons displaying images I have a couple of questions. I imagine your buttons are going to be loaded from a collection of some objects or something. By far, this is better than specifying each button in the XAML code.
I will assume your collection of objects has an ImagePath (or similarly named) property. The following should work out alright.
Load your ListBox with the Items, (see either http://www.WindowsClient.net for the old [Windows Forms] way, or read up on MVVM for the newer better way). Below is my listbox; ItemsSource is bound to the ImageCollection property on my ViewModel in this case. The items in my Imagecollection have an ImagePath property that is just a string file path to the image.
<ListBox ItemTemplate="{DynamicResource MyImageButton}" ItemsSource="{Binding ImageCollection}"/>
In Blend, you can create a DataTemplate by right clicking on the listBox, and going to Edit Additional Templates > Edit Generated Items (ItemTemplate).
From there you are just editing the layout of the items that will be created in the listbox. Below is my example of an item button with an image bound to the ImagePath property.
<DataTemplate x:Key="MyImageButton">
<Button Width="75">
<Button.Content>
<StackPanel>
<Image Source="{Binding ImagePath}" HorizontalAlignment="Left" Height="64" Width="64"/>
</StackPanel>
</Button.Content>
</Button>
</DataTemplate>
Let me know if you need more info and I can post some more resource links.
EDIT
Alright, so here is a simple little application that I made to illustrate how this can be done probably the easiest as possible. In this application, I have 3 classes:
ImageButton - It just consists of two string properties, ImagePath and ImageName.
ImageButtonCollection - Inherited from ObservableCollection, creates and adds 300 buttons (iterates 1 to 300 and sets ImagePath to "C:\Images\image{i}.png" and ImageName to "image{i}".
The MainWindow class - I will post the contents below.
MainWindow.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ImageButtons"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="MainWindow"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<CollectionViewSource x:Key="ImageButtonsCVS"/>
</Window.Resources>
<Grid>
<ListBox Height="311" HorizontalAlignment="Left" x:Name="ListBox1" VerticalAlignment="Top" Width="268" HorizontalContentAlignment="Stretch">
<ListBox.Resources>
<DataTemplate DataType="{x:Type local:ImageButton}">
<Border Background="#5A000000" CornerRadius="5">
<Grid Height="Auto">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.ColumnSpan="1" Height="30" Width="30" BorderBrush="#38FFFFFF" BorderThickness="1" Margin="5" Padding="0">
<Image Source="{Binding ImagePath}"/>
</Button>
<TextBlock Margin="0" TextWrapping="Wrap" Text="{Binding ImageName}" d:LayoutOverrides="Width, Height" Grid.Column="1" VerticalAlignment="Center" Foreground="White"/>
</Grid>
</Border>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemsSource>
<Binding Source="{StaticResource ImageButtonsCVS}"/>
</ListBox.ItemsSource>
</ListBox>
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="322,54,0,0" x:Name="Button1" VerticalAlignment="Top" Width="75" Click="CreateButtons" />
</Grid>
MainWindow.xaml.vb - I am more familiar with VB, but this can be easily ported to C# or whatever.
Class MainWindow
Private Sub CreateButtons(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs)
Dim ImageButtonCVS As CollectionViewSource = Me.FindResource("ImageButtonsCVS")
ImageButtonCVS.Source = New ImageButtonCollection
End Sub
End Class
So, the ListBoxes ItemsSource property is bound to the CollectionViewSource created in the Window.Resources. The ListBox also has in it's resources a DataTemplate for the ImageButton class. Anytime an ImageButton is displayed in that listbox, that template will be used. The buttons click event is set to the CreateButtons method in the codebehind.
That method finds the CollectionViewSource resource, and sets it's source to a new instance of the ImageButtonCollection class. Once that is done, the UI is notified of an update (since the ObservableCollection has built in UI notification) and changes accordingly displaying 300 buttons with a little textblock next to them with the image name.
If you run this, create a folder on your C drive with some images named "imageX.png" with x being a number 1 to 300. Below are the other two classes so you can create/compile/run it.
ImageButton class
Public Class ImageButton
Public Property ImagePath As String
Public Property ImageName As String
Public Sub New()
End Sub
Public Sub New(ByVal Path As String, ByVal Name As String)
Me.ImagePath = Path
Me.ImageName = Name
End Sub
End Class
ImageButtonCollection class
Imports System.Collections.ObjectModel
Public Class ImageButtonCollection
Inherits ObservableCollection(Of ImageButton)
Public Sub New()
For i As Integer = 1 To 300
Me.Add(New ImageButton(String.Format("C:\Images\image{0}.png", i), String.Format("Image{0}", i)))
Next
End Sub
End Class
You never specified how you wanted the image displayed. You may not want them to be in a listbox. The beauty of WPF is that once you get it working in a listBox or whatever ItemsControl, you can easily change to another ItemsControl, or even customize one. Go into the ListBox template and change the ItemsHost to use a uniform grid or to stack items horizontally instead of vertically.

How to create nestable object

At the begining I would like to say hello, so ... Hello. I need to create a nested object structure.
I've got an object (xaml page) like this
<navigation:Page x:Class="ItemTemplateExample.ContentItem"
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"
mc:Ignorable="d"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
d:DesignWidth="200" d:DesignHeight="20"
Title="ContentItem Page">
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="button1" />
<ContentControl Grid.Column="1" x:Name="content1" />
</Grid>
Now I would like to use it in nested structure. For Example
<local:ContentItem ButtonText="level 1">
<local:ContentItem ButtonText="level 2" />
<local:ContentItem ButtonText="level 2" />
<local:ContentItem ButtonText="level 2">
<local:ContentItem ButtonText="level 3" />
</local:ContentItem>
</local:ContentItem>
Where ButtonText will be known value (set when adding nested object) and Content of each object will be object of the same type. I have no idea how to start. Please give me some hint, exmaples. Thank You.
you would like to see HierarchicalDataTemplate in WPF
Seee here
Two possible solutions: a user control or a data template. The user control is probably the simplest to get to from where you are now, but the data template may be a better solution in the long run.
Adding a user control to a project is straightforward - Visual Studio has a template for that. You could just put the exact same Grid you've shown here inside your ContentItem user control's Xaml. And then you'd just need to define a property called ButtonText in the codebehind of your user control. This should do it:
public string ButtonText
{
get { return button1.Content.ToString(); }
set { button1.Content = value; }
}
That should let you use Xaml more or less exactly like you've shown.
The reason I'm suggesting that a data template might be better is that you might not want to hard-code the nested structure in Xaml. It's often nice to be able to generate such structure from data rather than baking it into the UI. However, if your structure is completely fixed, the approach you've asked for is probably OK.
Possibly related:Example of Nested Collections

Categories

Resources