Bind object's children to TextBox - c#

I using Entity Framework to manage my connection to the DB.
I have this example object:
Company
UniqueCode
Name
Address
I'll search the database using the UniqueCode to find a Company and after finding one, I want to show Name and Address on a couple of TextBoxes.
The example Xml is this one:
<TextBox x:CodeTextBox ...>
<Grid x:Name="ValuesGrid">
<TextBox x:Name="NameTextBox" ...>
<TextBox x:Name="AddressTextBox" ...>
</Grid>
And later, if the user modifies anything, I'll save the values to the DB.
So, what's the best way to show values of an object in a bunch of TextBoxes?
I'm thinking about using DataContext on the ValuesGrid, but I don't know how to make it work.

<Grid x:Name="ValuesGrid" DataContext="{Binding Company}">
<TextBox x:Name="NameTextBox" Text="{Binding Name}">
<TextBox x:Name="AddressTextBox" Text="{Binding Address}">
</Grid>
Where Company needs to be non-private property.

Related

Generic UserControl Using Reflection and Generalization

in my project i've wrote some UserControl, i'm trying to reuse code as much as possible.
For each Model in my project i create an UserControl that shows the CRUD (a simple form ) and another that shows the List (listBox)
Is possible to Generalize that (for different types of Models with different attributes)?
Using Generalizatione and Reflection is possible to create something like a generic UserControl_Crud and generic UserControl_List?
So in my page.xaml i can use something like
<LUC:UserContro_Crud l x:Name="EmployeeUserControl_List" />
<LUC:UserContro_Crud l x:Name="CarsUserControl_List" />
<LUC:UserContro_Crud l x:Name="FruitUserControl_List" />
and in the code behind
EmployeeUserControl_List.MyProperty.ItemsSource = EmployeetList;
CarsUserControl_List.MyProperty.ItemsSource = CarstList;
//MyProperty give me back just the listbox from my UserControl
or
FruitUserControl_List.MyProperty.ItemsSource = EmployeetList;
to show 3 lists with differnt properties
#HighCore #Nate Diamond
In that way, for any kind of my Model, i have to make a particular template. For example CrudPersonTemplate `
<!-- my crud-->
<DataTemplate x:Key="MyCrud">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,20,0,20">
<TextBlock Text="Code"/>
<TextBox x:Name="edtCode" InputScope="Number" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,20,0,20">
<TextBlock Text="Name" />
<TextBox x:Name="edtName" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="0,20,0,20">
<TextBlock Text="Sex" />
<TextBox x:Name="edtSex" />
</StackPanel>
</StackPanel>
</DataTemplate>
than (afeter registered it in the app.xaml as a resource) i can use it in Page.xaml just typing someting like
<ContentControl x:Name="MyTemplate" Content="{Binding}" ContentTemplate="{StaticResource MyCrud}" />
... but it's hard to manage field like "edtName" from page.xaml.cs or not? i have to write more code than using UserControl to do that...
How can I manage as well as possible this field of my form?
where is the difference with UserControl? i have to bind manually the ContentTemplate...
I'm looking for a generic solution in page.xaml, in the "view" i just want to call a generic template/userControl, and "automatically" choose the relative layout according with the object type associated in page.xaml.cs (i hope to explain it better, i apologize for my ignorance)

Using Icons in WPF Database Driven Application Results

I am attempting to make a WPF application. The application needs to use a "list view" to show results of queries to the database. I have been able to successfully create the application (GUI, database, LINQ, etc.), however, the display of my query results appear more "gridlike".
The specifications for the project below show that each record that appears in the results needs to have a green circle icon next to it. I have removed the actual results from the images below to keep the contents of the database private.
I don't have enough Reputation Points to post images, so I posted pictures so a sample/testing domain that I use. You can see screenshots here of the WPF app and code here:
http://digitalworkzone.com/WPF.html
What am I doing incorrectly? Is there something I need to add or modify to my code to be able to get the green circles and more of a "list" style to display my query results?
Understand the WPF content model. http://msdn.microsoft.com/en-us/library/bb613548.aspx
Anything that has a 'Content' property basically behaves in two ways. If the 'Content' is set to something that derives from UIElement, then the class will manage it's own presentation. Anything else, however, will just get .ToString() called, and it's text displayed instead.
What this means in the long run is that everything in WPF can display anything. If you want to show a button in a button, you can. For example:
<Button>
<Button.Content>
<Button Content="This will show as text" />
</Button.Content>
</Button>
The inner button will have text, but the outer button will show a Button because Button derives from UIElement and therefore will handle its own presentation.
In your picture examples above, you have ListBoxes/DataGrids that you want to fill in with graphical information. Try this out:
<ListBox HorizontalContentAlignment="Stretch">
<ListBox.Items>
<Button Content="One"/>
<Button Content="Two"/>
<Button Content="Three"/>
<Button Content="Four"/>
</ListBox.Items>
</ListBox>
Now you have a ListBox that shows Buttons instead of Text. You can take this a step further and contain the items in a stackpanel, for example:
<ListBox HorizontalContentAlignment="Stretch">
<ListBox.Items>
<StackPanel Orientation="Horizontal">
<Button Content="A button"/>
<Label Content="Some text" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button Content="A button"/>
<Label Content="Some text" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button Content="A button"/>
<Label Content="Some text" />
</StackPanel>
</ListBox.Items>
</ListBox>
Now we have items that contain a layout container (StackPanels, which then contains other elements).
However, if you set the ItemsSource elsewhere, you can actually use a DataTemplate to display the contents. A DataTemplate in effect targets a particular class and lays out it's contents as defined in XAML. Consider:
Code Behind:
public partial class MyWindow : UserControl {
public MyWindow() {
InitializeComponent();
MyListBox.ItemsSource = new List<Person> {
new Person("Sam", "Smith"),
new Person("Jim", "Henson"),
new Person("Betty", "White"),
};
}
XAML:
<ListBox HorizontalContentAlignment="Stretch" x:Name="MyListBox" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<Label Content="{Binding FirstName}"/>
<Label Content="{Binding LastName}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now when the Listbox displays, it will cycle through each of the items in the ItemsSource property, and then lay them out using the DataTemplate. It's possible to have the DataTemplate target specific classes by using the DataType property if you're using polymorphism (as in different types of people such as 'Cusomters' or 'Employees' which all derive from 'Person).
The problem with this approach is that you are setting the value of the items directly, which is bad form. It's better to define a class that handles all of the data for your view separately. Consider:
public class ViewModel {
// WPF will automatically read these properties using reflection.
public List<Person> People {
get {
return new List<Person> {
new Person("Sam", "Smith"),
new Person("Jim", "Henson"),
new Person("Betty", "White")
};
}
}
}
That will hold all the data for the view, now let's add it to the actual window. First we need to reference the namespace ('xmlns' means xml namespace):
<Window x:Class="Sharp.MyWindow"
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:lol="clr-namespace:Sharp">
The namespace is Sharp (the namespace where my stuff lives), and the alias we'll give it is lol. Now we attach our ViewModel class to the window by setting it to the DataContext property, as in:
<Window>
<Window.DataContext>
<lol:ViewModel />
</Window.DataContext>
</Window>
This makes all of the public properties on the ViewModel class available to the Window. This way, if we want to read the Persons information into our ListBox, we simply say:
<ListBox HorizontalContentAlignment="Stretch" ItemsSource="{Binding People}" >
...
</ListBox>
Notice that we say ItemsSource={Binding People}, which means 'scan the ViewModel for any public properties called 'People' and then retrieve those results. This is essentially the fundamentals behind the MVVM approach. You might have all of your business logic in one or many classes which handle the main application operation in a Model, but then you have a ViewModel which interacts with the Model and exposes the results as public properties. WPF automatically binds to those properties and presents them for your. The information just flows, rather than setting the values by force.
To really understand how WPF is supposed to work, you should take some time to understand the basics of MVVM. WPF was really designed with MVVM in mind, and so to really get how WPF is supposed to work, you really should take the time to get your head around it. Take a look at:
http://agilewarrior.wordpress.com/2011/01/11/simple-mvvm-walkthrough-part-i/ .
<ListBox ItemsSource="{Binding QueryResults}">
<ListBox.ItemsTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding ImageSource}"/>
<TextBlock Text="{Binding TextSource}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemsTemplate>
</ListBox>
Will work if you have a list of objects named QueryResults in your code behind. Each object needs to have an string property named ImageSource and a string property named TextSource.
However, since you only need to display a green circle icon for each of the items, you can hardcode the image source. The above will work if you want to have a different icon for each, though.
Also note that in order for this to work, you need to set the DataContext of the window to DataContext="{Binding RelativeSource={RelativeSource Self}}"

How to group together Textblock and Textbox

I am making the UIs for entering master data for various business entities (customer, etc). I run into this need to group together a TextBlock and a TextBox together frequently. i.e.
<Label Content="Civil Status:" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="civilStatusTextBox" Text="{Binding Path=CivilStatus, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
<Label Content="Company:" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />
<TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Left" Margin="3" Name="companyTextBox" Text="{Binding Path=Company, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" VerticalAlignment="Center" Width="120" />
Is there any way to do this with less typing? i.e.
<custom:LabeledTextBox Label="Civil Status:" Text="{Binding Path=CivilStatus, Mode=TwoWay, ValidatesOnExceptions=true, NotifyOnValidationError=true}" ... />
Or possibly, any libs which offer something like this?
EDIT : Forget the container Grid for a moment and assume it is a StackPanel.
Here's a step-by-step solution that I managed to put together. To set the stage, I'm going to assume we've got a very simple UserControl that has the following XAML content.
<UserControl x:Class="WpfApplication2.UserControl1" [ ... auto gen code removed ... ] >
<TextBox MinWidth="50" x:Name="TBox" />
</UserControl>
From an XAML that uses our UserControl we'd essentially want to set a data binding for the Text property on TBox. Idealy we could use a plain syntax like:
<local:UserControl1 TBox.Text="{Binding ...}" />
unfortunately I don't know any XAML syntax that would allow targeting an sub-element's property, so the next best thing would be to introduce a "staging" property in the UserControl itself and bind through that.
Since Binding only works for Dependency properties, the property we'll introduce needs to be a DependencyProperty. We'll also bind the Text property of TBox straight to our DependencyProperty from code.
The code-behind for the UserControl looks like this:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfApplication2
{
/// <summary>
/// Interaction logic for UserControl1.xaml
/// </summary>
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
// Set binding from code
this.TBox.DataContext = this;
this.TBox.SetBinding(TextBox.TextProperty, new Binding { Path = new PropertyPath("TBValue"), Mode = BindingMode.TwoWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged });
}
public static readonly DependencyProperty TBValueProperty = DependencyProperty.Register("TBValue", typeof(string), typeof(UserControl1));
public string TBValue
{
get { return this.GetValue(TBValueProperty) as string; }
set { this.SetValue(TBValueProperty, value); }
}
}
}
With this in place we can use the UserControl like this, binding to the TBValue property:
<local:UserControl1 TBValue="{Binding Path=Test, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
What you want to achieve (Master-Detail-Views) is actually well supported by Visual Studio out of the box. Open the following Menu structure : Project -> Add Data Source, then choose data source type Object. In the following, select the classes that you want to generate input fields for and finish the wizard.
Then, if not already open, open up your Data Sources tool window (Shift+Alt+D). You should see a DataSource of the type you just generated. To get a labelled field for each property of the object, open the source dropdown and click Details.
Note that the properties have such dropdowns as well, so that you can choose how you want to edit them (ComboBox, TextBox, Custom, no editor,...).
Now just drag the DataSource onto your window. You will get a Grid that's filled with all the labels and editors you desired. DataBinding and validation is also supported right away, so all you will have to do is set the generated Grid's DataContext.
Hope this saves you some work.
P.S. The screenshots are made in my german VS instance, still I thought they might help you identify the right dialogues / windows.

Use of DataTemplate

I'm quite new to C# and Windows Phone 7 for that sake, but none the less, I've thrown myself into trying to make a small app for myself. Here's my problem:
I'm trying to set up a DataTemplate that will position my Name and Drinks variables that I've declared in MainPage.xaml.cs. Here's my action when button1 is clicked:
private void button1_Click(object sender, RoutedEventArgs e)
{
string Name = participantName.Text;
int Drinks = 0;
listBox1.Items.Add(Name + Drinks);
}
And here is my DataTemplate from MainPage.xaml
<ListBox Height="Auto" HorizontalAlignment="Stretch" Margin="7,74,0,0" Name="listBox1" VerticalAlignment="Stretch" Width="Auto">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Height="132">
<TextBlock Text="{Binding Path=Name}" FontSize="35" />
<StackPanel Width="370">
<TextBlock Text="{Binding Path=Drinks}" FontSize="35" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The problem is that my data is not shown. It works perfectly without the DataTemplate, but as soon as I use it, my text simply doesn't get through. Your help is very much appreciated.
The template itself is ok. The bindings on the template, though, are currently incorrect.
When you add a new item to the list box, you are just adding a plain old string (which is currently missing a space, BTW.) Your bindings, though, expect the object in the list to have a Name property and a Drinks property, which of course the string class does not have.
The usual solution here is to logically separate your data model from your presentation, by creating a class to store the data itself (probably PersonDrink, with the appropriate Name and Drinks properties) and then adding those objects to the list.
You should read up on the MVVM pattern, as it provides an excellent way to ensure that changes in your data are reflected in your view, and visa versa.
http://amarchandra.wordpress.com/2011/12/18/binding-multiple-object-in-wp7-using-listbox/
Here is a sample for binding data using a datatemplate. I hope this might help you.

Populate WPF DataGrid dynamically

My program needs to take input from a fire alarm panel over a serial connection and populate a list based on it. When a new device is reported from the panel, the statement is parsed and the device is added to the device List.
That part of my program all works fine and dandy. The problem now is displaying the list of fire alarm devices to the user.
I am hoping to do this using a DataGrid (unless there's a better way?) but am not able to find a lot of helpful documentation on WPF DataGrids that is relevant to me. Most of what's out there seems to be displaying data from a database. Mine however, needs to update every time the panel spits out a new device description and the device List in my program is appended.
I see I can set AutoGenerateColumns to true and initially display my list just fine. BUT, I would like to customize the column headers. Also this doesn't update when the List is appended so I'm not sure how to "refresh" it.
When AutoGenerateColumns is false, I get no data displayed. When the program runs it shows me the correct number of rows corresponding to the number of items in my list, but no data. Wondering how/if I need to link each column with its corresponding device data member?
Lastly, how do you format a DataGrid to look pretty through re-sizes? I can set column width and all that, but what I want is a few of the columns to be fixed width, and the middle column to expand to fill remaining available area.
This is my first stab at WPF. Any help would be greatly appreciated!
Personaly i dont like DataGrid much. Yes they are easier to bind and they offer built-in resize and sorting options but they are not as flexible as an ItemsControl with a good DataTemplating on your Objects. Let me explain myself.
I tend to populate my ItemsControl with an ObservableCollection. Then, i use a DataTemplate in order to tell my ItemsControl how to display my custom items.
Your CustomObjects can be Modeles objects if your doing MVVM.
If your list is binded to an ObservableCollection, the Added and Removed items will appear dynamicly into your list, which is what i belive your trying to do.
For the column size, you could put a Grid specifying GridColumns width to fixed Width for some columns and * for others so they fill the remaining space.
Here's an alternative to the GridView
I use a ScrollViewer around my ItemControl so if the ItemsControl get too big, you can scroll it.
The ItemsControl's ItemSource is binded to your FireAlarms's ObservableCollection.
The WrapPanel in the ItemsControl will contain each DataTemplate. It's Width is binded to his parent (or ancestor if you will) which is an ItemsControl
<ScrollViewer
Grid.Row="x"
Grid.Column="y"
VerticalScrollBarVisibility="Auto"
Margin="5">
<ItemsControl
BorderBrush="DarkBlue"
BorderThickness="2"
ItemsSource="{Binding Path=FireAlarms}"
ItemTemplate="{StaticResource FireAlarmsTemplate}"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel
Orientation="Horizontal"
Width="{Binding RelativeSource=
{RelativeSource FindAncestor,
AncestorType={x:Type ItemsControl}},
Path=ActualWidth}"
>
</WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
Ok then you need a DataTemplate. You can put the DataTemplate in your windows's ressource or in a DataDictionnary. Lets say you have a class :
FireAlarm
{
Public String AlarmInfo1;
Public String AlarmInfo2;
Public String AlarmInfo3;
}
Here could be a nice DataTemplate to start with :
<DataTemplate x:Key="FireAlarms">
<Border
BorderBrush="SteelBlue"
Background="LightBlue"
BorderThickness="2"
Margin="10"
Padding="10">
<StackPanel
Orientation="Vertical"
>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition Width="5"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label
Grid.ColumnSpan="3"
Grid.Row="0"
Content="{Binding Path=AlarmName}"
Margin="5,-5,5,10"
FontWeight="Bold"
FontSize="16"
HorizontalContentAlignment="Center"
HorizontalAlignment="Center">
</Label>
<TextBlock
Text="Alarm information 1" Grid.Row="1" Grid.Column="0" />
<TextBox
Text="{Binding Path=AlarmInfo1}"
Grid.Column="2"
Grid.Row="1"
>
</TextBox>
<TextBlock
Text="Alarm information 2" Grid.Row="2" Grid.Column="0" />
<TextBox
Text="{Binding Path=AlarmInfo2}"
Grid.Column="2"
Grid.Row="2"
>
</TextBox>
<TextBlock
Text="Alarm information 3" Grid.Row="3" Grid.Column="0" />
<TextBox
Text="{Binding Path=AlarmInfo3}"
Grid.Column="2"
Grid.Row="3"
>
</TextBox>
</Grid>
</StackPanel>
</Border>
</DataTemplate>
Ok I hope this is usefull for you. My Template will generate 1 square per alarm. If you'd rather have it in a Table like a GridView, you could modify this using a verticaly oriented stack panel and use a grid with variable // invariable column width but since you asked for anything usefull, i tough i'd guive you something fun to work with!
Enjoy!
Some time back I wrote a post Create DataGrid in WPF using code take a look at it, it will help you in creating data grid in dynamic scenarios like yours
If you a dynamic grid (meaning the number and design of the columns are unknown at design time), I do it with code-behind with binding. I generally use the MVVM pattern (if you not familiar with this, I really recommend reading into it since it is THE pattern when working with WPF).
1) You have to set Auto-Generate columns to false of course and give grid a name (here myDataGrid)
GridViewDataColumn newColumn= new GridViewDataColumn();
myDataGrid.Columns.Add(newColumn)
This will add the column to your grid. Now the column will be empty. Now it depends on your data how to fill it with data. If you bind to a known property on the items, do:
newColumn.Binding = new Binding("knownPropertyName");
In most cases though, you do not know the propertyname and bind to an element in the collection.
Then it would like more:
myDoubleCollection.Add(someDoubleValue); //do this for each item in the itemssource of the grid
int index=myDoubleCollection.Count-1;
newColumn.Binding = new Binding(string.Format("myDoubleCollection[{0}]",index));
So this works also.
Another thing to keep in mind is the deletion of columns. This requires some extra work.
That's a lot of questions rolled into one! I suggest you do a bit more background research before asking questions. I would recommend that your read this codeproject article I wrote about the WPF DataGrid a while back:
http://www.codeproject.com/KB/WPF/WPFDataGridExamples.aspx
It will answer most of your questions for you!
Take a look at the MVVM pattern, it'll be a huge help as you create this application.
What you want is an ObservableCollection in the ViewModel. You'll bind the ItemsSource property of the datagrid to this collection. Then have your columns bind to various properties on to display them. Whenever this ObservableCollection has an item appended, your front end should update automatically.
To have a column autosize, set the Width="*".
Here's a sample of a datagrid with MVVM
<DataGrid ItemsSource="{Binding FireAlarmCollection}" SelectedItem="{Binding SelectedFireAlarm, Mode=TwoWay}" AutoGenerateColumns="True" CanUserSortColumns="True" HorizontalScrollBarVisibility="Visible" CanUserResizeColumns="True">
</DataGrid>
As you continue your effort, post separate questions for each issue.

Categories