Xaml Binding outside itemtemplate - silverlight

I would like to bind data of my listbox. Imagine I have something like :
<ListBox ItemsSource="{Binding MyList}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text={Binding Value} />
<TextBlock Text={Binding AbsoluteValue} />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
MyList contains an observable collection of an object that has a property named "Value"
AbsoluteValue is a property of the view model, as the MyList property.
Of course, the seconde textbox will have always the same value, but it is what I want :)
How can I tell the binding that the datacontext is not the same for the second textbox ?
Thanks in advance for any help
EDIT : my real sample is a StackPanel.
I've tryed
private void StackPanel_Loaded(object sender, RoutedEventArgs e)
{
StackPanel stackPanel = sender as StackPanel;
stackPanel.SetBinding(StackPanel.VisibilityProperty, new Binding("Loaded") { Source = DataContext, Mode = BindingMode.TwoWay });
}
but it's not working

XAML:
<TextBlock x:Name="tbAbsoluteValue" Loaded="AbsoluteValue_Loaded" />
Codebehind:
void AbsoluteValue_Loaded(object sender, RoutedEventArgs e)
{
TextBlock absoluteValue = sender as TextBlock;
absoluteValue.SetBinding(TextBlock.TextProperty, new Binding("AbsoluteValue") { Source = VIEW_MODEL_OBJECT, Mode = BindingMode.TwoWay });
}
That's one way to achieve what you want, you could also use a converter too, or create a StaticResource in your Resources for the VM and bind to that as a source.

Related

XAML bind SelectedItem to a DataContext.listbox reference

I stuck in a Problem:
I have a PopUp window, its DataContext points to an object which holds a reference to a ListBox (reftolistbox).
I managed to create a working binding with this codebehind code:
private void ID_Loaded(object sender, RoutedEventArgs e)
{
Binding myBinding = new Binding("id");
myBinding.Source = ((myclass)DataContext).reftolistbox;
myBinding.Path = new System.Windows.PropertyPath("SelectedItem.Name");
BindingOperations.SetBinding(ID, ComboBox.TextProperty, myBinding);
}
I want to replace the above code with a XAML Solution,
here is a list i tried but no one worked.
<Combobox ...
Text="{Binding Source=DataContext.reftolistbox, Path=SelectedItem.Name }"
Text="{Binding reftolistbox.SelectedItem.Name }"
Text="{Binding Path=DataContext.reftolistbox.SelectedItem.Name}"
Need a XAML Solution, what am I doing wrong?
XAML only binds to properties
DataContext:
{ public ListBox reftolistbox { get; set; } }
working binding in XAML:
Text="{Binding reftolistbox.SelectedItem.Name }"

Access the TextBlock 's text at run time in DataTemplate of ItemsControl in WPF

Iam displaying messages in my WPF application
when a new message is added to the messages, i need to highlight it.so i want to dynamically get the text added to TextBlock
i have the xaml like this
<ItemsControl Name="DialogItemsControl" ItemsSource="{Binding Messages, Mode=OneWay}" Background="Transparent"
BorderBrush="Transparent" TargetUpdated="DialogItemsControl_TargetUpdated">
<ItemsControl.ItemTemplate><!-- For ever message -->
<DataTemplate>
<Grid Margin="0,0,0,20">
<ItemsControl Name="SubDialogItemsControl"
Foreground="{DynamicResource ButtonTextBrush}"
ItemsSource="{Binding Lines,NotifyOnTargetUpdated=True}"
Margin="0,0,0,12"
Grid.Column="0">
<ItemsControl.ItemTemplate><!-- For every line -->
<DataTemplate>
<TextBlock Name="DialogMessageText"
Text="{Binding NotifyOnTargetUpdated=True}"
VerticalAlignment="Top"
Margin="0,2,0,2"
TextTrimming="WordEllipsis"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
and the code in the codebehind class is like this:
private void DialogItemsControl_TargetUpdated(object sender, System.Windows.Data.DataTransferEventArgs e)
{
ItemsControl itemControl = sender as ItemsControl;
ContentPresenter dp = itemControl.ItemContainerGenerator.ContainerFromItem(itemControl.Items.CurrentItem) as ContentPresenter;
// Finding textBlock from the DataTemplate that is set on that ContentPresenter
DataTemplate myDataTemplate = dp.ContentTemplate;
ItemsControl itc = (ItemsControl)myDataTemplate.FindName("SubDialogItemsControl", dp);
if (itc != null && itc.ItemContainerGenerator.Status == System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
{
ContentPresenter cp = itc.ItemContainerGenerator.ContainerFromIndex(0) as ContentPresenter;
DataTemplate dt = cp.ContentTemplate;
TextBlock tb = dt.LoadContent() as TextBlock;
tb.TargetUpdated += new EventHandler<System.Windows.Data.DataTransferEventArgs>(myTextBlock_TargetUpdated);
}
}
void myTextBlock_TargetUpdated(object sender, System.Windows.Data.DataTransferEventArgs e)
{
TextBlock tb = sender as TextBlock;
//When i access the text property of tb, its showing null, how to get the text
}
When i access the text property of textblock in the target updated event of textblock, its showing null, how to read the text.
Thanks in advance
You tackle the problem from the wrong angle (and probably add a memory leak in the process since I don't see you unsubscribing to the event).
You need to create a Custom TextBlock, overriding the metadata of the Text property so that it changes the Background for a few seconds when the text string changes (through PropertyChangedCallback).
And then use that custom TextBlock in the DataTemplate of your ItemsControl.
EDIT - I thought other people could need this feature so here is a working example:
public class CustomTextBlock : TextBlock
{
static CustomTextBlock()
{
TextProperty.OverrideMetadata(typeof(CustomTextBlock), new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(
(dpo, dpce) =>
{
//Flash the background to yellow for 2 seconds
var myTxtblk = dpo as CustomTextBlock;
if (myTxtblk != null)
{
myTxtblk.Background = Brushes.Yellow;
Task.Factory.StartNew(
() =>
{
Thread.Sleep(2000);
Application.Current.Dispatcher.Invoke(
new Action(() =>
{
myTxtblk.Background = Brushes.Transparent;
}));
});
}
})));
}
}
Then you need to declare the right xmlns namespace in your XAML view, and you use it like a regular TextBlock:
<local:CustomTextBlock Text="{Binding MyDynamicText}"/>
It will flash yellow when MyDynamicText is modified (provided it raises PropertyChanged).

TextBlock MouseDown URL - How get my url in my code behind?

I ve a list from sharepoint and i collect from this list an hyperlink.
As i want my textbox to be like an hyperlink I ve added an event on mousedown to open this hyperlink, My concern is how to collect this hyperlink in the codebehind with the sender.
For the moment I've just hide this hyperlink in the tooltip maybe i can manage this differently any suggestion will be grantly appreciated.
My point so far, i don't know how to get this tooltip in the code behind.
Thanks
My XAML Code :
<ListBox Name="ListboxTips" ItemsSource="{Binding}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=Picture}" Height="20"></Image>
<TextBlock MouseDown="TextBlock_MouseDown_URL" TextDecorations="Underline"
Margin="10,10,20,10" Width="160" TextWrapping="Wrap"
Text="{Binding Path=TitleTip}"
ToolTip="{Binding Path=URL}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My code behind :
foreach (SPSClient.ListItem item in TipsList)
{
var tips = new Tips();
tips.TitleTip = item.FieldValues.Values.ElementAt(1).ToString();
tips.App = item.FieldValues.Values.ElementAt(4).ToString();
// get the Hyperlink field URL value
tips.URL = ((FieldUrlValue)(item["LinkDoc"])).Url.ToString();
//should collect the description of the url
//tips.URLdesc = ((FieldUrlValue)(item["LinkDoc"])).Description.ToString();
tips.Picture = item.FieldValues.Values.ElementAt(4).ToString();
colTips.Add(tips);
}
ListboxTips.DataContext = colTips;
....
private void TextBlock_MouseDown_URL(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
//string test = (ToolTip)(sender as Control).ToString();
System.Diagnostics.Process.Start("http://www.link.com");
//System.Diagnostics.Process.Start(test);
}
Thanks a lot,
You can just access the property directly. It is not elegant, but will work!
private void TextBlock_MouseDown_URL(object sender, MouseButtonEventArgs e)
{
TextBlock txtBlock = sender as TexBlock;
// just access the property
string url = txtBlock.ToolTip as string;
}
A more elegant approach might be to use a Button, Hyperlink or something that exposes a Command, so that you can bind the 'click' action to a command on your view model that performs the action you wish to execute.
usually you stick any data you want to trespass somewhere to Tag attribute.
<TextBlock .. Tag="{Binding Path=URL}" />
This is easily retrievable as a public property:
private void TextBlock_MouseDown_URL(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
var tb = sender as TextBlock;
if(tb != null)
{
var neededUrl = tb.Tag;
}
}

Binding TextBlock based on selection in ComboBox

When I make selection in ComboBox, and then type some text in TextBox, I want to have visible AutoSuggestion list of ID or FirstName or LastName (based on ComboBox Selection) that contains typed string in TextBox. Like this, now it works only for FirstName.
I have problem to somehow set dynamically binding for TextBlock.
Please Help.
Thanks in advance! Marina
I have ComboBox:
<ComboBox Height="23" Name="cbAttrib" Width="120" Margin="0,8,0,0">
<ComboBoxItem>ID</ComboBoxItem>
<ComboBoxItem>FirstName</ComboBoxItem>
<ComboBoxItem>LastName</ComboBoxItem>
</ComboBox>
I have TextBox:
<TextBox Name="txtSearch" TextChanged="txtAutoSuggestName_TextChanged"/>
And this ListBox:
<ListBox Name="listBoxSuggestion" Visibility="Hidden" SelectionChanged="ListBox_SelectionChanged">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock DataContext="{Binding FirstName}"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
and in code I have this methods:
private void txtAutoSuggestName_TextChanged(object sender, TextChangedEventArgs e)
{
listBoxSuggestion.Items.Clear();
if (txtSearch.Text != "")
{
ComboBoxItem cb = (ComboBoxItem)cbAttrib.SelectedItem;
Collection<Person> namelist = proxy.PersonSearch(txtSearch.Text, cb.Content.ToString());
if (namelist.Count > 0)
{
listBoxSuggestion.Visibility = Visibility.Visible;
foreach (var obj in namelist)
{
listBoxSuggestion.Items.Add(obj);
}
}
}
else
{
listBoxSuggestion.Visibility = Visibility.Hidden;
}
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count > 0)
{
txtSearch.Text = (e.AddedItems[0] as Person).FirstName.ToString();
listBoxSuggestion.Visibility = System.Windows.Visibility.Hidden;
}
}
You are not binding the Text so nothing will display
You just bind the DataContext, which does nothing if there are no additional bindings which will be relative to it. Just swap that (or add Text="{Binding}" which will bind to the DataContext which is the FirstName) and if your logic is correct it should work.
(Instead of clearing and adding to Items you should just set the ItemsSource instead. listBoxSuggestion.ItemsSource = namelist;)
Edit: To make the binding work for different suggestions change the binding path to Value and make the ItemsSource a collection of some simple objects with a Value property (e.g. use LINQ and anonymous objects).

How to Identify button for list item

How do i access the object UserNames, that is bound to the list??
What i did so far:
Item of the list is object in my case:
new List<UserNames>();
this.users.Add(new UserNames() {Id = 1, UserName = "name 1"});
I am using data template for which i have label and button.
My List is as follows:
<ListBox Grid.Column="1" Grid.Row="1" Name="listBox1" ItemsSource="{Binding}" SelectedValuePath="Id">
<ListBox.ItemTemplate>
<DataTemplate>
<WrapPanel Orientation="Vertical">
<StackPanel>
<Label Content="{Binding UserName}" />
</StackPanel>
<StackPanel Name="ButtonStackPanel">
<Button Name="MyButton" Content="Click Me" Click="MyButton_Click">
</Button>
</StackPanel>
</WrapPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Where my method for Button is. As you can see i did try to utilise the parent option, but without sucess
private void MyButton_Click(object sender, RoutedEventArgs e)
{
//StackPanel panel = (StackPanel)((Button)sender).Parent;
//WrapPanel wrapPanel = (WrapPanel) panel.Parent;
//ListItem listItem = (ListItem) wrapPanel.Parent;
//ListBox box = (ListBox) listItem.Parent;
//UserNames itemToReport = (UserNames) (box.SelectedItem);
//MessageBox.Show(itemToReport.UserName);
}
You can use the Button's DataContext, since it will be your UserName object
private void MyButton_Click(object sender, RoutedEventArgs e)
{
Button b = sender as Button;
UserNames data = b.DataContext as UserNames;
MessageBox.Show(data.UserName);
}
I've always thought that with WPF, your application is the DataContext, while the UI objects like Buttons, ListBoxes, TextBoxes, etc are simply a pretty layer that sits on top of the DataContext to allow the User to interact with it.
In the XAML, set the Tag property to the current item.
In the click handler, cast it back.
Usernames user = (sender as Button).Tag as Usernames;
To bind a datacollection it is often easiest to use an ObservableCollection (if the data is changing runtime). When you do the binding you have to define a datacontext, a datasoure and a datapath. I will advice you to read some more about binding on MSDN :D
This will work for you -
MessageBox.Show(((sender as Button).DataContext as UserNames).UserName);

Resources