Why is my XAML ToggleButton invisible to the code-behind? - c#

I have a ToggleButton in MainPage.xaml:
<ToggleButton x:Name="ColorToggle" Background="{Binding Background, ElementName=LayoutRoot}" ToolTipService.ToolTip="Change Toolbar Color">
...yet when I try to access it from MainPage.xaml.cs:
private void SaveAppBarColorSelected(object sender, TappedRoutedEventArgs e)
{
PhotraxUtils.SetLocalSetting(PhotraxConsts.APPBARBUTTON_COLOR, ColorToggle.Background.ToString());
}
...I get, "The name 'ColorToggle' does not exist in the current context"
Why is that?

Only controls from the root context are available in code-behind. If you place your named control inside a template, it won't be available. You can traverse the controls tree using VisualTreeHelper and other methods in this case.
Or better yet, just use MVVM.

Related

C# Snackbar as Dialog

I want to use the Snackbar from any thread. I declared my Snackbar as i should her;
https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/wiki/Snackbar
The Wiki says that I can only access the Snackbar from a Dispatcher thread, but how do I implement this?
the user control xaml;
<materialDesign:DialogHost SnackbarMessageQueue="{Binding ElementName=MySnackbar, Path=MessageQueue}" Identifier="DialogSnackbar">
<Grid>
<!-- app content here -->
<materialDesign:Snackbar x:Name="MySnackbar" MessageQueue="{materialDesign:MessageQueue}" />
</Grid>
</materialDesign:DialogHost>
to show a dialog, but i also want to hand over a message;
implementation from https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/wiki/Dialogs
public static async void ShowDialog()
{
var result = await DialogHost.Show("test", "DialogSnackbar", ExtendedOpenedEventHandler, ExtendedClosingEventHandler);
}
private static void ExtendedOpenedEventHandler(object sender, DialogOpenedEventArgs eventargs)
{
}
private static void ExtendedClosingEventHandler(object sender, DialogClosingEventArgs eventArgs)
{
}
the current message is displayed really weird
All seems to look right for me.
In your ShowDialog() method you only pass a string "test" as content for your DialogHost and you didn't define a DataTemplate in DialogHost.DialogContentTemplate nor a DataTemplateSelector in DialogHost.DialogContentTemplateSelector. So the default behavior of ContentControl kicks in when there is no ContentTemplate or ContentTemplateSelector defined and you don't pass the XAML elements directly as Content. This results in a TextBlock element being created for the dialog content where your string is bound to its Text property. This is exactly what your picture shows.
So to get a different result than what your picture shows you need to either pass directly your XAML elements which you want to show in your dialog (with a root container element and all buttons your dialog needs) or define a DataTemplate or DataTemplateSelector for your DialogHost in your XAML, if you want to use it in a MVVM scenario.
Look at this example from the repo if you need a hint how you can implement this.
You can use:
App.Current.Dispatcher.Invoke(()=>{
//Add the control related code stuff here
});
with the help of #Anateus i get to this solution;
in my MainWindow.xaml i declared this;
<materialDesign:DialogHost VerticalAlignment="Bottom"
HorizontalAlignment="Center"
Identifier="DialogSnackbar">
</materialDesign:DialogHost>
The DialogSnackbarView.xaml - the content of the dialog;
<UserControl ...>
<Grid>
<materialDesign:Snackbar x:Name="MySnackbar"
MessageQueue="{materialDesign:MessageQueue}" />
</Grid>
</UserControl>
to show the Dialog everywhere;
var view = new DialogSnackbarView();
view.MySnackbar.MessageQueue.Enqueue("test");
await DialogHost.Show(view, "DialogSnackbar");

How to handle events from ResourceDictionary without using ResourceDictionary Code-Behind?

I would like help regarding how to handle events from controls in a ResourceDictionary (e.g. Styles.xaml) without using ResourceDictionary Code-Behind (e.g. Styles.xaml.cs), mainly because I want the Styles.xaml to just be there for styling.
My scenario is, I have a Custom Page which uses a ResourceDictionary for DataTemplate styles (I am using a TemplateSelector). However, the problem I am currently having is for handling events. For example:
I have this in my Styles.xaml:
.
.
<Button Click="Button_Click"/>
.
And I declare this in the CustomPage.xaml.cs :
private void Button_Click(object sender, RoutedEventArgs e)
{
// some code
}
However, it does not work. Is there any way to explicitly tell that I want to use that particular Event Handler for the button's click event? Additionally, is it possible to have different handlers for each page e.g.
CustomPage2.xaml.cs:
private void Button_Click(object sender, RoutedEventArgs e)
{
// some different code from CustomPage.xaml.cs
}
Thank you!
The answer is simple: do not handle events such a way. Use bindings instead (especially, if you're using data templates). E.g., for Button:
<Button Command="{Binding MyCommand}">
where MyCommand is a ICommand-implemented instance from your data context.
If you're not familiar with data bindings in WPF, start read from here.

wpf busyindicator not showing up

I have a wpf busy indicator like this on my window:
<Grid><Controls1:BusyIndicator x:Name="busyIndicator2" IsBusy="False" Content="Please wait....." Visibility="Hidden"/>
</Grid>
And in the button click I m trying to set the visiblity,isBusy property of indicator to true and visible.
void button_click(object sender, RoutedEventArgs e)
{
busyIndicator2.Visibility = System.Windows.Visibility.Visible;
busyIndicator2.IsBusy = true;
}
but the indicaotr is not showing up.
Any idea why?
I've always wrapped other wpf content with the BusyIndicator, it then shows up centered over that content.
<BusyIndicator...>
<Grid>....</Grid>
</BusyIndicator>
Try wrapping your layout control in the BusyIndicator and see if that does what you are after.
Where is the BusyIndicator defined? For example, if your XAML looks like:
<Grid>
<BusyIndicator ...>
</BusyIndicator>
<ListBox ...>
</ListBox>
</Grid>
You'll never see the BusyIndicator because it's behind the ListBox. I would recommend using the BusyIndicator as suggested by Chris, otherwise, make sure it's not inadvertently behind other visuals.

How click a TextBlock in DataTemplate?

This is my XAML code:
<ListBox ItemsSource="{Binding}" Name="listBox">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<StackPanel Width="370">
<TextBlock Text="{Binding AuthorName}" x:Name="author" MouseEventLeftDown="click"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And the Click Handler
private void click(object sender, RoutedEventArgs e)
{
if(author.Text.Equals("Hi"))
{
// Do Something Special
}
}
The error is:
Error: The name 'author' does not exist in the current context
But I don't understand what is causing this error or why it is occurring.
Your TextBlock with the Name author doesn't exist in the scope of your click handler because it's in a DataTemplate. What's happening is that the author TextBlock is created once for every one of your data items (Presumably an Author class or a Book class of some kind), so you literally can have dozens of controls named author.
You are better off casting your sender in your click handler to a text box and then checking its text property. Something like this:
private void click(object sender, RoutedEventArgs args)
{
var textBox = sender as TextBox;
if(textBox == null)
return;
if(textBox.Text.Equals("hi"))
{
// Do Something Crazy!
}
}
It's probably better to use a UI element designed for touch, such as a HyperlinkButton or a Button. You can style these any way you would like to - especially if you use Expression Blend - but it is good design to include some visual feedback about the Touch.
Also - I'm not sure about your == code - you're comparing the sender (a UI element) against some string expression?
First off, your TextBlock is defined in a DataTemplate; try x:Name instead of Name on your TextBlock.
Secondly it might be quite tricky to click your TextBlock since you will have to press an exact pixel in your TextBlock. To make it easier to click your TextBlock you might want to put a Background on your TextBlock, so it will be a lot easier to click. You can even make the background transparent:
Background="Transparent"
use the gesture listener for create an event handler like "tap" or double" or whatever.
Use this...
private void click(object sender, RoutedEventArgs e)
{
var author = (TextBlock)sender;
if (author.Text.Equals("Hi"))
{
// Do Something Special
}
}

Silverlight 4: How to find source UI element from contextmenu's menuitem_click?

I have a datagrid and I added silverlight 4 toolkit contextmenu to textbox in datagrid as follows. When users right click on the textbox, contextmenu is being displayed. When users click the menu item with Header "Test", "MenuItem_Click" is getting executed. Now I want to access the textbox from the MenuItem_Click and modify its properties like background etc. Is there anyway to find textbox element(which is contextmenu's parent) from MenuItem_Click event?
It appears to me that I am missing something very simple.
<my:DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox Text="{Binding AcctId}"
Style="{StaticResource documentTextBoxStyle}"
ToolTipService.ToolTip="Right Click to modify parameters" >
<toolkit:ContextMenuService.ContextMenu >
<toolkit:ContextMenu >
<toolkit:MenuItem Header="Test" Click="MenuItem_Click"/>
</toolkit:ContextMenu>
</toolkit:ContextMenuService.ContextMenu>
</TextBox>
</DataTemplate>
There's really no need for a workaround, it's as simple as using the databinding:
(sender as MenuItem).DataContext as TextBox
Will give you the TextBox you're after. (Storing stuff in the Tag field is really not something you want to clutter your code with.)
Though I did not find a solution to this, I found couple of workarounds
Traverse the visual tree and findout the textbox
Modify the code in control toolkit sources to expose the internal member 'Owner' as a public Property which contains reference to the owner of the context menu, in my case, the textbox.
I wonder why SL toolkit guys made the owner to be internal not public. Probably their idea is to manage 'ContextMenu' only through 'ContextMenuService' but unfortunately ContextMenuService doesnt give the Owner. Hopefully SL toolkit guys will give us a way to get the owner of the context menu in future releases.
I'm not sure if this works in Silverlight, but I had a similar issue with WPF recently. If you use the ContextMenu's PlacementTarget property, it should return the element that was used to open the ContextMenu.
All I can suggest is giving your MenuItem a Tag with it's parent's TextBlock name like this:
EDIT: Can't figure out how to paste in Xaml, but I'm sure you know how to add this.
Then in your click event you find the TextBlock:
private void MenuItem_TextBlockClick(object sender, RoutedEventArgs e)
{
MenuItem menuItem = (MenuItem)sender;
TextBlock textBlock = this.FindName((string)menuItem.Tag) as TextBlock;
/// do something
}
The issue I found was the parent of the MenuItem is ContextMenu, which is fine. But once you try and get the Parent of the ContextMenu it just crashes.

Categories