I have an autocompletebox with these databindings:
<sdk:AutoCompleteBox Height="23" HorizontalAlignment="Left" Margin="80,21,0,0" Name="comboBox_clients" VerticalAlignment="Top" Width="171" ItemsSource="{Binding}" IsTextCompletionEnabled="True" IsDropDownOpen="True" ValueMemberPath="client_code">
<sdk:AutoCompleteBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding client_code}" Name="left" Width="70" />
<TextBlock Text="{Binding client_name}" Name="right" Width="250" />
</StackPanel>
</DataTemplate>
</sdk:AutoCompleteBox.ItemTemplate>
</sdk:AutoCompleteBox>
It works like I want, but it appears on a form that gets loaded a lot, and because the autocompletebox has a few thousand items, it takes two or three seconds at initial load to get all of the strings indexed/in order/whatever once I bind it with the appropriate observablecollection.
Instead I want to keep the autocompletebox object as a global so the few second indexing time only happens on the first load, and then during subsequent openings of the window, the autocompletebox on the form can just be set to the global one. How would I duplicate this databinding structure in code?
Firstly create a AutoComplete and set its DataTemplate (The below links lead you the way).
You can't get an instance of a DataTemplate codebehind side,but...
https://stackoverflow.com/a/7101581/413032
https://stackoverflow.com/a/72158/413032
But if I were you in spite of of creating datatemplate in codebehind creating a small resource and reaching it from code behind make things easier.
Related
Let me explain so I have a wpf application I used a listBox with a template. This template contains a TextBlock and a ComboBox. When running the application, everything goes well, my list is initialized correctly. But then I would like to retrieve the values of my TextBlock and my comboBox and I don't understand how I can achieve this.
I am attaching the part of my XAML code that deals with this listBox :
<ListBox x:Name="ListBoxEnv" Grid.Row="1"
d:ItemsSource="{d:SampleData ItemCount=5}" Width="460"
SelectionChanged="ListBoxEnv_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="TxtBlockEnv"
VerticalAlignment="Center" HorizontalAlignment="Left"
Text="{Binding EnvName}"/>
<ComboBox x:Name="ComboBoxEnv"
VerticalAlignment="Center" HorizontalAlignment="Left"
ItemsSource="{Binding EnvListValue}"
Margin="100,2,0,2" Width="200"
SelectionChanged="ComboBoxEnv_SelectionChanged"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The EnvName property is readonly because it is bound to TextBlock, so you can ignore it. Change binding to: Text="{Binding EnvName, Mode=OneTime}" to save the app resources.
However to extract selected environment in every combo in the list you need to add to ComboBox template: SelectedItem={Binding SelectedEnv} and add new property to SampleData
for example
public MyEnvironmentClass SelectedEnv {get; set;}
I've recently moved from Windows Forms to WPF. I started with Reed Copsey's series 'Better User and Developer Experiences – From Windows Forms to WPF with MVVM'. On the 4th part of the series, the following code should fill text boxes with data:
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Path=Feed.Title, Mode=OneWay}" />
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Path=Feed.Link.AbsoluteUri, Mode=OneWay}" />
<TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Path=Feed.Description, Mode=OneWay}"/>
I tried to use this template-of-code to 'update a target (TextBlock.Text) as the source (TextBox.Text) updates', and that was my full XAML code:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="608.134" Width="768.284">
<Grid>
<Button Content="Button" HorizontalAlignment="Left" Height="28" Margin="442,56,0,0" VerticalAlignment="Top" Width="139" Click="Button_Click_1"/>
<TextBox x:Name="TextBox1" HorizontalAlignment="Left" Height="28" Margin="56,56,0,0" TextWrapping="Wrap" Text="TextBox1" VerticalAlignment="Top" Width="237"/>
<TextBlock HorizontalAlignment="Left" Height="66" Margin="56,168,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="285"
Text="{Binding Path=TextBox1.Text, Mode = OneWay}"/>
</Grid>
</Window>
The expected value for the text of the TextBlock was "TextBox1" (TextBox1.Text), but the TextBlock text was actually null!
So, I checked what triggers source updates, and decided to change the binding mode to TwoWay, but I got the same result!
At last, I found "How to: Control When the TextBox Text Updates the Source" that shows how to do that. According to what Reed Copsey said in this part of his series:
Less code means less to maintain, less to test, and less to worry about.
and according to the source found on MSDN:
<Label>Enter a Name:</Label>
<TextBox>
<TextBox.Text>
<Binding Source="{StaticResource myDataSource}" Path="Name"
UpdateSourceTrigger="PropertyChanged"/>
</TextBox.Text>
</TextBox>
<Label>The name you entered:</Label>
<TextBlock Text="{Binding Source={StaticResource myDataSource}, Path=Name}"/>
I'll be typing (roughly) the same amount of code. And such a mission (to change TextBlock by TextBox changes) can be accomplished using the normal event handlers. So my questions are:
If the same mission can be accomplished with roughly the same amount of code, what makes WPF data binding so special?
What was wrong with my first code?
In the above MSDN code, they had to type an XAML code for both source and target. If I wanted the source to be a value inside a class, is it possible to accomplish such mission? And how?
Any help will be appreciated,
Thanks in advance.
You first attempt is incorrect as the Binding path is relative to the DataContext of the TextBlock. You are trying to bind to a specific element, so you can use ElementName to specify the source and then the path is relative to this:
Text="{Binding ElementName=TextBox1, Path=Text}"
The idiomatic approach to WPF is to use MVVM. In this situation, both the TextBox and TextBlock would be bound to a property on the View Model.
The changing of the text in the TextBox would update this property which in turn would update the TextBlock. Your View Model is free from WPF View concerns and can be unit tested without involving WPF.
I have created a few text boxes that have to be added as children to my DockPanel. I have given this DockPanel a name and then when I try in my code to use this name, Intellisense does not give me any results. How do I select DockPanel and then add its children?
I want to select it and add some text boxes to it as its children. For example: nameLocationPanel.Children.Add(new TextBox());
This is the top part of my XAML code that contains the DockPanel. It already has some text boxes, but I want to add more in my C# code.
<ListBox ItemContainerStyle="{StaticResource lbStyle}" Name="searchList" BorderBrush="#FF898989" BorderThickness="2" MouseUp="searchList_MouseUp" MouseDoubleClick="searchList_MouseDoubleClick" Visibility="Visible">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<DockPanel Name="nameLocationPanel">
<TextBlock FontSize="14" HorizontalAlignment="Left" Text="{Binding Path=FirstName}"/>
<TextBlock FontSize="14" HorizontalAlignment="Left" Text=" "/>
<TextBlock FontSize="14" HorizontalAlignment="Left" Text="{Binding Path=LastName}"/>
<TextBlock HorizontalAlignment="Right" Text="{Binding Path=Location}"/>
</DockPanel>
It is within a DataTemplate, you can't select it by name at all as it doesn't exist in your Window, it's just a Template definition that will get repeated so there isn't 1 dockpanel but N, N being equal to how many items there are in your listbox and there could well be 0 dockpanels.
What exactly are you trying to achieve? Odds are you're going about it backward.
You cannot access to the DockPanel because it is a part of a DataTemplate. It is generated for every item in your ListBox so it is impossible to access to a single instance of it.
To add additional items to the DockPanel it is necessary to do it via something like a binding in XAML or a special UserControl. But it depend always on the ListBoxItem.
really simple problem, but I guess I have just the wrong definition of combobox:
I'd like to get a simple thing like:
http://www.c-sharpcorner.com/uploadfile/mahesh/combobox-in-silverlight/
But whenever I add a combobox (or a listbox) and set the itemssource, it shows directly all items and I dont have a textbox-like selection.
My approach was quite simple:
In XAML I define:
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Center" Style="{StaticResource styleStdWidth}" Text="Spieler 1:" />
<ListBox x:Name="lsbPlayerOne" ItemTemplate="{StaticResource dtName}" Width="300" />
<TextBox x:Name="txtPlayerOnePoints" Style="{StaticResource stylePlayerWidth}" />
</StackPanel>
<DataTemplate x:Name="dtName">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" TextWrapping="Wrap" FontSize="35" FontWeight="Bold" x:Name="txbname"/>
</StackPanel>
</DataTemplate>
And in Code behind I just set the ItemsSource with a List, which has data.
Since the ListBox gets bigger every time I add a item, it gets uglier and uglier.
Am I missing a property, which I didnt find? I did not see anything...
Sorry for the confusing question :)
P.S.: I tried the same as in the example shown in the link. Sadly I cant open the sample project.
Matthias Müller
Your question is unclear. But you are not implementing a combobox in the code you have shown. Why don't you use a combobox and set your itemsource to the list that contains the fields you want to use?
<ComboBox ItemSource={Binding Names}/>
I have a page that has a listbox with the following item template as follows:
<ListBox x:Name="test">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid MaxHeight="108" Margin="0,0,0,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="4" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Rectangle Height="108" Grid.Column="0" Fill="{Binding Color}"/>
<Image Source="{Binding Image}" Height="108" Width="108" Grid.Column="1" HorizontalAlignment="Left" Stretch="UniformToFill"/>
<StackPanel Grid.Column="2">
<TextBlock Text="{Binding Title}" TextWrapping="NoWrap" />
<TextBlock Text="{Binding SubHeading}" TextWrapping="NoWrap" />
<TextBlock Text="{Binding Body}" TextWrapping="Wrap" />
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
On the OnNavigatedTo event of the page, I set the item source of the list box to an observable collection of about 20 items.
All is well and the list is populated, however when I scroll up or down the list, the items appear to look out of sync on the UI. e.g the text that was shown on the first list item appears on the last item in the list box, sometimes there's duplicates, and everytime you swipe up or down the items are different.
I have debugged the listbox items, and I can see that correct objects are being bound to the right items. So it's only what is shown on the UI that is incorrect.
I have also tried explicitly using the standard stackpanel as opposed to a virtualizationstackpanel and that works around the issue by making sure all items are loaded in memory.
I don't believe that removing virtualization is the answer. There must be a root cause. However it may be acceptable as my listbox will never really contain more than 30 items.
On another page, I do the same thing with the silverlight toolkit longlistselector, and have the same issue. However I am not sure of how to remove virtualization on a longlistselector.
So to summarize, what might be the underlying issue that causes the listbox items to not update the UI properly when scrolling? If removing virtualization is the only answer, how may I do this on the longlistselector?
Thanks for anyhelp on this.
Maybe it is some sort this problem? (jumpy ListBox while scrolling)
As it turns out, it was a binding issue, and nothing to to with the listbox whatsoever.
I was (unknowingly) removing the binding of some properties in the item template, after I had bound to them (in some other bit of code) Therefore every time the listbox recycled the containers for new items, it could not update it with the correct info.
Thanks all for your help