How to create nestable object - c#

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

Related

MVVM how to pass object from main window to user control? [duplicate]

This question already has answers here:
What is DataContext for?
(4 answers)
Closed 4 months ago.
sorry about this question. I know MVVM exist for many years but each time I try to code something with it I face the same issue again and again ans I'm still looking for a real good tutorial about this.
Let's consider we have a main window (MainWindow.xaml) with its view model (MainViewModel.cs).
This window has a grid, in my grid I define 2 user controls. Whatever it is. One is on the left, one on the right. On my main window I have create, in MainViewModel.cs an engine:
internal class MainWindowViewModel
{
public MainWindowViewModel()
{
QCEngine qcEngine = new();
}
}
This engine is my unique model and contains a complex code that read data. Whatever. This engine has a public list of value. I want to display these values on my left and right panels in different ways. Again whatever. The display is not my issue.
My issue is how I pass this list or the entire engine reference to my panels? I'm really lost. I can do this in few seconds with any classic WinForms but I never figure out how to do in MVVM. I'm at this moment where I give up MVVM to do classic WinForms. This time I want to understand.
Can you help me?
My QC engine is a RFID reader. It already works fine as console application. All parameters are in a config file. the idea of the interface is to give more flexibility to the reader. Having a nice result screen, a setting screen, some interactions.
<Window x:Class="Beper.QCTable.Control.View.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:view="clr-namespace:Beper.QCTable.Control.View"
xmlns:viewmodel="clr-namespace:Beper.QCTable.Control.ViewModel"
mc:Ignorable="d"
Title="MainWindow"
Height="450"
Width="800">
<Window.DataContext>
<viewmodel:MainWindowViewModel />
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Menu -->
<Menu Grid.Row="0" FontSize="20">
<MenuItem Header="_Menu">
<MenuItem Header="_Advanced"/>
</MenuItem>
</Menu>
<!--Header-->
<StackPanel Grid.Row="1" Background="Orange">
<TextBlock FontSize="20">
Header
</TextBlock>
</StackPanel>
<!--Body-->
<Grid Grid.Row="2">
<view:TabPanel/>
</Grid>
<!--Status Bar-->
<StatusBar Grid.Row="3" FontSize="20">
<StatusBarItem>
Status
</StatusBarItem>
</StatusBar>
</Grid>
</Window>
Focus on tab panel:
public class TabPanelViewModel
{
public ObservableCollection<TabItem> Tabs { get; set; } = new ObservableCollection<TabItem>();
public TabPanelViewModel()
{
Tabs.Add(new TabItem { Header = "One", Content = "One's content" });
Tabs.Add(new TabItem { Header = "Two", Content = "Two's content" });
}
}
I cannot chare the engine code but, really, it is just a list of keys (RFID keys / EPC). This is the only public data. I want to display this list of key by group under my tabs.
Passing "this list or the entire engine reference" to the view defats the purpose of implementing the MVVM design pattern in the first place.
What you should do is to use the engine to prepare and set the state of your app/view in your view model.
The controls in the views should then bind to properties of the view model that contains, and effetively defines, the current state.

Add additional content to the custom user Control WPF

I have a custom user control which contains ToolBar with buttons. I want these buttons and toolbar to be the base content of the control and assign it to different views. But for some views, in some cases, I need to add additional tools to the toolbar, or additional toolbar itself at the end of the already existing ones.
I tried control template and dependency property binding. In control template case I must move my already existing buttons from Content to template and that makes my buttons inaccessible from the code behind (I need to expose these buttons with public properties for other views to add event handlers on them later because different views need to have different responses on the same events).
As for the dependency property and ContentPresenter, well it just did not work and I have no idea why.
here is my XAML for UserControl:
<UserControl x:Class="Syllogia.Desktop.Controls.SylToolBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
xmlns:local="clr-namespace:Syllogia.Desktop.Controls"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="150">
<Grid>
<telerik:RadToolBar Grid.Column="0" Grid.Row="0" x:Name="MainToolBar" AutoHideOverflowButton="True">
<telerik:RadButton x:Name="AddButton">
<Image Source="icons/Pixel/plus_math_30px.png"/>
</telerik:RadButton>
<telerik:RadButton x:Name="EditButton">
<Image x:Name="ToggleButtonImage" Source="icons/Pixel/edit_32px.png"/>
</telerik:RadButton>
<telerik:RadButton x:Name="DeleteButton">
<Image Source="icons/Pixel/erase.png"/>
</telerik:RadButton>
<telerik:RadButton x:Name="PrintButton">
<Image Source="icons/Pixel/print_30px.png"/>
</telerik:RadButton>
<telerik:RadButton x:Name="RefreshButton">
<Image Source="icons/Pixel/refresh_32px.png"/>
</telerik:RadButton>
<Grid x:Name="GridAdditionalContent">
</Grid>
</telerik:RadToolBar>
</Grid>
question 1: Is there another way to add additional content to this control from the other controls?
question 2: Is there a way to expose buttons which are declared inside a template?
I am fairly new to WPF and there may be some detail which I was not able to search and find.
In any case, Thank you for your help and sorry if I am asking stupid questions here.

WPF/MVVM - Initialize image from XAML and bind to property in ViewModel

I have an application written in WPF MVVM.
I want to initialize an embedded image from XAML (so that I can see it in the designer) but also bind it to the ViewModel so I can manipulate from code.
I can successfully initialize it like this:
<Image x:Name="Image1" Source="pack://application:,,,/images/image1.png" Height="200" Width="55" Opacity="0.35">
How do I bind it to the ViewModel?
If you want to see some data in design time you can define DesignTime viewmodel.
<Window
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=designTimeViewModels:DesignViewModel,
IsDesignTimeCreatable=True}"
/>
And to Bind Image Source use folowing code:
<Image Source="{Binding DisplayedImagePath}" />
ViewModel:
public string DisplayedImagePath
{
get { return "/AssemblyName;component/Images/ImageName.jpg"; }
}
from this topic: Binding an Image in WPF MVVM
You could use FallbackValue...
<BitmapImage x:Key="Image1" UriSource="pack://application:,,,/images/image1.png" />
<Image x:Name="Image1" Source={Binding Image1, FallbackValue={StaticResource Image1}}" />
This has the possible downside of having your image how up at run time if the conditions for use of the fallback value is triggered; so you would need to avoid that situation.

WPF C# Two-Way Data Bind Not Working

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.

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.

Categories

Resources