changing textblock to textbox loses data bindings - - c#

this is a wpf/c# app - I have one grid where I used text boxes and the data bindings were fine. I later built another grid using textblocks. both worked well. but when I changed the textblocks in the second grid into textboxes, all but one stopped displaying data.
I copied both the c# LINQ code and the XAML code that provide the data for the bindings, recompiled, saved it to NotePad++, and closed VS(8). After reopening the project, I reinserted the code, but I still got no data.
Any ideas that would help would be greatly appreciated.
Here's the c# code
var vendDetail = from v in dbC.Vendors
where v.VendorID == vendorid
select new
{
v.Address1,
v.Address2,
CSZ = v.City + ", " + v.State + " " + v.Zip,
v.Phone,
v.Fax,
v.Contact,
v.Terms,
v.eMail
};
grVendorData.DataContext = vendDetail;
And the XAML code:
<TextBox x:Name="txtVendorAddr1"
Text="{Binding Path= Address1}"
Background="AliceBlue"
Grid.Row="2"
Grid.Column="1"/>
<TextBox x:Name="txtVendorAddr2"
Text="{Binding Path= Address2}"
Grid.Row="3"
Grid.Column="1"
Background="AliceBlue"/>
<Label Content="City"
Grid.Row="4"
Grid.Column="0"/>
<TextBox x:Name="txtVendorCity"
Text="{Binding Path= CSZ}"
Grid.Row="4"
Grid.Column="1"/>
<Label Content="Phone"
Grid.Row="1"
Grid.Column="0"/>
<TextBox x:Name="txtVendorPhone"
Text="{Binding Path = Phone}"
Grid.Row="1"
Grid.Column="1"/>
<Label Content="Fax"
Grid.Column="2"
/>
<TextBox Text="{Binding Path = Fax}"
Grid.Row="0"
Grid.Column="3" />
<Label Content="Terms"
Grid.Row="2"
Grid.Column="2"/>
<TextBox Text="{Binding Path = Terms}"
Grid.Row="2"
Grid.Column="3"/>
<Label Content="Notes"
Grid.Row="3"
Grid.Column="2" />
<TextBox Text="{Binding Path = Notes}"
Grid.Row="3"
Grid.Column="3"
Grid.RowSpan="2"
TextWrapping="WrapWithOverflow" />
<Label Content="eMail"
Grid.Row="1"
Grid.Column="2" />
<TextBox Text="{Binding Path = eMail}"
Grid.Row="1"
Grid.Column="3"/>

You cannot bind to anonymous types, which is why the binding worked after you began selecting the whole record.

Related

WPF Issue with same ALT hotkey

I have a window with 3 textboxes and labels with following properties:
<Label x:Name="label" Content="_Label" Target="{Binding ElementName=textBox}"/>
<Label x:Name="label1" Content="Label"/>
<Label x:Name="label2" Content="_Label" Target="{Binding ElementName=textBox2}"/>
See this image
You can see that "label" and "label2" have the same ALT + L key but different Target property. When I focus textBox middle and I press ALT + L I need that textBox2 is focues (like in MFC). I can't use code behide because I was made about 200 windows.
Thanks a lot!
I think if you really need with out code behind or ViewModel you can do it by adding the same short cut to Label1 like below,
<Label x:Name="label" Grid.Row="0" Content="_Label" Target="{Binding ElementName=textBox}"/>
<Label x:Name="label1" Grid.Row="1" Content="_Label" Target="{Binding ElementName=textBox1}"/>
<Label x:Name="label2" Grid.Row="2" Content="_Label" Target="{Binding ElementName=textBox2}"/>
<TextBox x:Name="textBox" Grid.Column="1" Grid.Row="0"/>
<TextBox x:Name="textBox1" Grid.Column="1" Grid.Row="1"/>
<TextBox x:Name="textBox2" Grid.Column="1" Grid.Row="2"/>
If you can make a ViewModel then InputBinding with KeyBinding can make it work.

C# UWP Get Items in ListView's ItemTemplate

I am trying to access textblocks and textboxes in a listview, but cannot get them in C# code because they are inside an ItemTemplate and DataTemplate. Here is a sample of the XAML code:
<ListView x:Name="VehicleList" HorizontalAlignment="Center" Height="120" Margin="0" VerticalAlignment="Center" Width="1119" Background="{ThemeResource CheckBoxDisabledForegroundThemeBrush}" SelectionChanged="VehicleList_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<Grid x:Name="VehicleGrid" Height="52" Width="1117" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="318*"/>
<ColumnDefinition Width="425*"/>
<ColumnDefinition Width="366*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="Year" Grid.Column="0" TextWrapping="Wrap" Text="{Binding Year}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="321" FontSize="26.667"/>
<TextBlock x:Name="Make" Grid.Column="1" TextWrapping="Wrap" Text="{Binding Make}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="425" FontSize="26.667" />
<TextBlock x:Name="Model" Grid.Column="2" TextWrapping="Wrap" Text="{Binding Model}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="366" FontSize="26.667"/>
<TextBox x:Name="AddYear" Grid.Column="0" TextWrapping="Wrap" Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="321" FontSize="26.667" Visibility="Collapsed"/>
<TextBox x:Name="AddMake" Grid.Column="1" TextWrapping="Wrap" Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="425" FontSize="26.667" Visibility="Collapsed"/>
<TextBox x:Name="AddModel" Grid.Column="2" TextWrapping="Wrap" Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="366" FontSize="26.667" Visibility="Collapsed"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Is there anyway to get the items inside the DataTemplate?
Your problem is generic to all XAML flavors, same in WPF and Silverlight. The problem is your DataTemplate. Keep in mind that XAML will inject the contents of your DataTemplate once for each item in your list. That means your names can only exist within the scope of an instance of your DataTemplate.
If you have do code behind for your template, you might do better by creating a UserControl. See below for an example:
<!-- most boiler plate code skipped -->
<UserControl x:Class="MyProject.VehicleListItem">
<Grid x:Name="VehicleGrid" Height="52" Width="1117" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="318*"/>
<ColumnDefinition Width="425*"/>
<ColumnDefinition Width="366*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="Year" Grid.Column="0" TextWrapping="Wrap" Text="{Binding Year}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="321" FontSize="26.667"/>
<TextBlock x:Name="Make" Grid.Column="1" TextWrapping="Wrap" Text="{Binding Make}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="425" FontSize="26.667" />
<TextBlock x:Name="Model" Grid.Column="2" TextWrapping="Wrap" Text="{Binding Model}" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,20,0,0" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="366" FontSize="26.667"/>
<TextBox x:Name="AddYear" Grid.Column="0" TextWrapping="Wrap" Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="321" FontSize="26.667" Visibility="Collapsed"/>
<TextBox x:Name="AddMake" Grid.Column="1" TextWrapping="Wrap" Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="425" FontSize="26.667" Visibility="Collapsed"/>
<TextBox x:Name="AddModel" Grid.Column="2" TextWrapping="Wrap" Text="TextBlock" HorizontalAlignment="Center" VerticalAlignment="Center" Height="52" Grid.ColumnSpan="1" TextAlignment="Center" Width="366" FontSize="26.667" Visibility="Collapsed"/>
</Grid>
</UserControl>
That let's you do everything you need to do from a UserControl that can be instantiated, has it's own code behind, etc. You can get that working exactly how you want, and then reference it when you need it in your list like this:
<ListView x:Name="VehicleList" HorizontalAlignment="Center" Height="120" Margin="0" VerticalAlignment="Center" Width="1119" Background="{ThemeResource CheckBoxDisabledForegroundThemeBrush}" SelectionChanged="VehicleList_SelectionChanged">
<ListView.ItemTemplate>
<DataTemplate>
<myProject:VehicleListItem/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The ListView will assign a vehicle item to the DataContext of your user control and everything will work just like you designed it to.
There is a way to get at the visual tree in code behind but it is very convoluted. Essentially you need to use the ListView.ItemContainerGenerator and call ContainerFromItem(dataItem) (ref) and then walk down the visual tree you get from that. It's not only a serious pain to do, there's no guarantee all of the API will be accessible from WPF to UWP or SilverLight. The cleanest solution is to break up the code into independent pieces.
Another solution, which probably is even more clean that what I proposed is to take advantage of your bound objects. ListView.SelectedItem returns your object that is bound to the DataTemplate. Just get the values from that object. If you have a ViewModel that includes properties for AddYear, AddMake, and AddModel then it makes a lot of the work easier to do since you aren't dealing with XAML at all.
If it's okay for you to do this on a button-click; you could use the CommandParameter or traverse the VisualTree like these two links suggest:
How to get text from TextBox inside ListViewItem's DataTemplate
How to get the value out of a textbox in XAML?
UserControl
It sounds like a UserControl is what you are looking for.
Project → Add UserControl
It should be easy since you already have the XAML design. The code behind will look something like this:
public class VehicleView : UserControl
{
// Year
public static readonly DependencyProperty YearProperty =
DependencyProperty.Register("Year", typeof(int), typeof(VehicleView),
new PropertyMetadata());
public int Year
{
get { return (int)GetValue(YearProperty); }
set { SetValue(YearProperty, value); }
}
// Make
public static readonly DependencyProperty MakeProperty =
DependencyProperty.Register("Make", typeof(string), typeof(VehicleView),
new PropertyMetadata("None"));
public string Make
{
get { return (string)GetValue(MakeProperty); }
set { SetValue(MakeProperty, value); }
}
// Model
public static readonly DependencyProperty ModelProperty =
DependencyProperty.Register("Model", typeof(string), typeof(VehicleView),
new PropertyMetadata("None"));
public string Model
{
get { return (string)GetValue(ModelProperty); }
set { SetValue(ModelProperty, value); }
}
public VehicleView()
{
InitializeComponent();
}
}
Binding words the same way. Just name the UserControl with x:Name. Something like:
<UserControl x:Name="vehicleview"
x:Class="MyProjectClass"
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"
mc:Ignorable="d">
<Grid>
<!-- Here's where your ListView goes. -->
<TextBox Text="{Binding ElementName=vehicleview, Path=Model}"/>
<Grid>
</UserControl>
As i can see you have used bindings.
On VehicleList_SelectionChanged you can do the following
List<YouClass-Model> selectedItems = VehicleList.SelectedItems.Cast<YouClass-Model>().ToList();
or if you use ItemClicked EventHandler
YouClass-Model itemClicked = (YouClass-Model)e.ClickedItem)
That way you can load the binded data. ex itemClicked.Model
Also make sure that you binded your data correctly
Data binding overview
INotifyPropertyChanged.PropertyChanged
To get the UI control from the index or data, use listView.ContainerFromIndex or listView.ContainerFromItem. This is the accepted way in UWP.
try this code:
private void myListView_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
ListItemData data = args.Item as ListItemData;
ListViewItem a = args.ItemContainer as ListViewItem;
var b = a.ContentTemplateRoot as Grid;
var txtBlock =b.FindName("txtTitle") as TextBlock;
txtBlock.Text = data.Title;
TextRange textRange = new TextRange()
{
StartIndex = 1,
Length = 3
};
TextHighlighter highlighter = new TextHighlighter()
{
Background = new SolidColorBrush(Colors.Yellow),
Ranges = { textRange }
};
txtBlock.TextHighlighters.Add(highlighter);
}

TabIndex property is not working in Windows Phone 8 application

I am setting the TabIndex propertry inside the Grid.
My code is `
<Grid Margin="30,12" Grid.Row="1" Grid.Column="1" Background="White">
<TextBlock Foreground="#FF858585" Grid.Row="1" Grid.Column="0" Text="{Binding Path=LocalizedResources.Password, Source={StaticResource LocalizedStrings}}"
Padding="10,8" x:Name="tb_pwd" />
<PasswordBox TabIndex="1" Password="" Background="Transparent" BorderBrush="#FF1ba1e2"
Style="{StaticResource PwdBoxStyle}" Grid.Row="1" MaxLength="15" GotFocus="txtpwd_GotFocus_1" LostFocus="txtpwd_LostFocus_1" x:Name="txtpwd">
</PasswordBox>
</Grid>
<Grid Grid.Row="2" Grid.Column="1" Margin="30,0" Background="White">
<TextBlock Foreground="#FF858585" Grid.Row="2" Grid.Column="0" Text="{Binding Path=LocalizedResources.Domain, Source={StaticResource LocalizedStrings}}"
Padding="10,8" x:Name="tb_domain" />
<TextBox TabIndex="2" Text="" Background="Transparent" BorderBrush="#FF1ba1e2"
Style="{StaticResource TxtBoxStyle}"
Grid.Row="2" GotFocus="txtdomain_GotFocus_1"
LostFocus="txtdomain_LostFocus_1"
Grid.Column="1" x:Name="txtdomain" MaxLength="15" />
</Grid>`
But in emulator when i write username and click tab it does not work.
Any suggestions?
The SIP (keyboard) on windows phone does not include a tab key and so there is not support internally for this.
The de-facto convention in apps is to advance the tab focus from code when the user presses the enter key.
There are lots of resources online that show how to do this and helper classes to make it really simple.

Adding and editing item in datagrid with same controls

Hei,
I'm using MVVM with my wpf application. I have DataGrid what shows list of items and i have binded SelectedItem to CurrentSequence propery in my ViewModel. When CurrentSequence changes properties of that object are shown in other controls for editing.
Heres my xaml:
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Path=ColorSettingsSequences}"
SelectedItem="{Binding Path=CurrentSequence, Mode=TwoWay}">
.... more things here ...
</DataGrid>
<StackPanel Grid.Column="0" Grid.Row="0">
<Grid>
<Label Content="Start temperature (°C)" Height="28" HorizontalAlignment="Left" x:Name="lblSeqStartTemp" VerticalAlignment="Top" />
<TextBox Height="23" Margin="0,28,10,0" x:Name="tbSeqStartTemp" VerticalAlignment="Top" Text="{Binding Path=CurrentSequence.StartTemp}" />
</Grid>
<Grid>
<Label Content="Start color" Height="28" HorizontalAlignment="Left" x:Name="lblSeqHue" VerticalAlignment="Top" />
<xctk:ColorPicker Margin="0,28,10,0" x:Name="clrpSeqHue" SelectedColor="{Binding Path=CurrentSequence.StartHue, Converter={StaticResource hueToColor}, ConverterParameter=False}" ShowStandardColors="False" />
</Grid>
</StackPanel>
<StackPanel Grid.Column="1" Grid.Row="0">
<Grid>
<Label Content="End temperature (°C)" Height="28" HorizontalAlignment="Left" x:Name="lblSeqEndTemp" VerticalAlignment="Top" />
<TextBox Height="23" Margin="0,28,10,0" x:Name="tbSeqEndTemp" VerticalAlignment="Top" Text="{Binding Path=CurrentSequence.EndTemp}" />
</Grid>
<Grid>
<Label Content="End color" Height="28" HorizontalAlignment="Left" x:Name="lblSeqEndHue" VerticalAlignment="Top" />
<xctk:ColorPicker Margin="0,28,10,0" x:Name="clrpSeqEndHue" SelectedColor="{Binding Path=CurrentSequence.EndHue, Converter={StaticResource hueToColor}, ConverterParameter=False}" ShowStandardColors="False" />
</Grid>
</StackPanel>
Code:
private ColorSettingsSequencesSequence _currentSequence;
public ColorSettingsSequencesSequence CurrentSequence
{
get
{
return this._currentSequence;
}
set
{
this._currentSequence = value;
OnPropertyChanged("CurrentSequence");
}
}
Now the questions is, how could i add a button what would save changes or add a totally new item. I know how to do one or another, but what about 2 together with same controls...
You can create a property on your view model which is of type ColorSettingsSequencesSequence named CurrentSequenceEdit and you can set the value of this object upon changing selection.
Then upon click of an add button you can create a new ColorSettingsSequencesSequence object and set it to the value of CurrentSequenceEdit.
Typically on a new object you'll have an ID that is not set or is set to a negative number which you can use in the Save command to determine whether it needs added to the grid or not.

WPF DataTemplate method binding with parameter

I have a custom ItemTemplate for a ListBox and I need to "bind" a TextBlock to some special method / property.
My ListBox Source is an ObservableCollection<SearchResultItem>. SearchResultItem containing some properties.
The text need to change based on the value of another object. E.G if this object equals "foo" I need the text value to call the method GetProperty("foo") on the SearchResultItem to get the correct value.
Here is a sample of code:
<DataTemplate>
..
//Here is a Label bound to the Date Property of the SearchResultItem
<Label Margin="2,2,2,0" Grid.Row="0" Grid.Column="2" Content="{Binding Path=Date}" HorizontalAlignment="Right" HorizontalContentAlignment="Right" />
//Here is the textblock that needs to call the method with the parameter based on the value of the other object.
<TextBlock Margin="2,2,2,0" TextTrimming="CharacterEllipsis" Grid.Row="0" Grid.Column="1" Text="I need some help there" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="Black"/>
..
</DataTemplate>
Do you have any idea on how to do that or a better way to do it?
Edit:
-Let's assume SearchResultItem comes from an external library and only exposes the GetProperty method.
-Let's say the "foo" value comes from ConfigurationManager.AppSettings["propertyName"]; if it helps.
OK, because your properties never change, here's one solution. You can do this via another property on your SearchResultItem class:
public string MyTextBinding
{
get
{
return myDictionary.ContainsKey("foo") ? return myDictionary["foo"] : return "myDictionary doesn't contain foo";
}
}
Then just bind your textbox to this property:
<DataTemplate>
<Label Margin="2,2,2,0" Grid.Row="0" Grid.Column="2" Content="{Binding Path=Date}" HorizontalAlignment="Right" HorizontalContentAlignment="Right" />
<TextBlock Margin="2,2,2,0" TextTrimming="CharacterEllipsis" Grid.Row="0" Grid.Column="1" Text="{Binding Path=MyTextBinding, Mode=OneWay}" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="Black"/>
</DataTemplate>
Just use a IValueConverter that takes a SearchResultItem and return the expected text
<TextBlock Margin="2,2,2,0" TextTrimming="CharacterEllipsis"
Grid.Row="0" Grid.Column="1"
Text="{Binding Path=.,
Converter={StaticResource PropertyValueFromSearchResultItemConverter},
ConverterParameter=Foo}"
HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="Black"/>

Categories

Resources