Binding Click action to custom xaml component - c#

I have the following custom control in XAML:
<Button x:Name="button" HorizontalAlignment="Left" Margin="0,0,0,0" VerticalAlignment="Center" Width="200">
<StackPanel Orientation="Horizontal" Width="170">
<TextBlock Text="" FontFamily="Segoe UI Symbol" Visibility="{Binding isFolder, Converter={StaticResource BooleanToVisibilityConverter}}"/>
<TextBlock Text="" FontFamily="Segoe UI Symbol" Foreground="Gold" Visibility="{Binding isFolder, Converter={StaticResource InverseBooleanToVisibilityConverter}}"/>
<TextBlock Text="{Binding title}" Margin="5,0" Foreground="Black"/>
</StackPanel>
I want to bind click action on isFolder. So I created a xaml page and in code behind I added the control as follow:
MyControl item = new MyControl();
item.DataContext = context;
// item.click += context.isFolder ? folderAction : nonFolderAction
There is no item.click. How can I add delegate to click based on boolean value?

You can use relaycommands where you can specify the condition when the command should be executed.
For example: (in your case)
In your viewmodel: (do this)
private RelayCommand myCommandInViewModel;
public RelayCommand MyCommandInViewModel
{
get { return myCommandInViewModel?? (myCommandInViewModel= new RelayCommand(myCommandInViewModelAction,()=> { return isFolder; })); }
}
where myCommandInViewModelAction has your method definition.
Above is the advised way of doing.
Else you can have another way where in the button.Click event you can get the datacontext of the sender and check for isFolder property in it.
private void someClickEvent(object sender, RoutedEventArgs e)
{
var buttonDataContext = (sender as Button).DataContext;
if(buttonDataContext.isFolder)
{
doSomeThing();
}
else
{
return;
}
}

Related

C# WIN UI 3: I have combobox with custom-typed observable collection as itemssource. Need help getting selected item

very new to C# WPF/WIN UI. My combobox displays my collection perfectly. But now when I want to do something with what the user selected I can't find the correct syntax in my 'SelectionChanged' event handler. I want to get the 'Market_ID' somehow. (FYI, I am not using MVVM yet as I don't understand how to implement, but I will learn. (really liking c#))
<ComboBox x:Name="cmbMarketID" PlaceholderText="Select Market ID" Width="500" Margin="5,5,0,0" RelativePanel.RightOf="border1" RelativePanel.Below="cmbState" ItemsSource="{x:Bind marketIdent}" SelectionChanged="cmbMarketID_SelectionChanged" SelectedItem="{Binding Market_ID}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="cmbo_market_ID" Text="{Binding Market_ID}" Width="15" TextAlignment="Right"/>
<TextBlock Text="{Binding Product}" Width="145" Margin="10,0,10,0" FontWeight="SemiBold"/>
<TextBlock Text="{Binding Company}" Width="70" Margin="10,0,10,0"/>
<TextBlock Text="{Binding System}" Margin="10,0,10,0"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
Here is the event handler: (I used a simple string first, and that worked, but now I need to use a typed-collection)
private void cmbMarketID_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (cmbMarketID.SelectedIndex == -1)
{
// Do not execute event
}
else
{
//string mktid = cmbMarketID.SelectedItem.ToString().Substring(0, 2).TrimEnd();
//string mktid = cmbMarketID.SelectedItem;
int mktid = (int)cmbMarketID.SelectedItem(); <-------what should the correct syntax be here?
//v_metric_mktid = mktid;
}
}
Cast the SelectedItem property to your type.
For example, if marketIdent is an IEnumerable<YourClass>:
var item = cmbMarketID.SelectedItem as YourClass;
Or if marketIdent is an IEnumerable<int>:
if (mbMarketID.SelectedItem != null)
{
var mktid = (int)mbMarketID.SelectedItem;
}

LongListSelector set image visibility on selection change

I have a LongListSelector with some textblocksand images inside.
How can I set the Image's visibility programmatically?
I have them set to collapsed and I want to enable them on selection_changed event of the LongListSelector.
XAML:
<phone:LongListSelector Name="LongListSel" Margin="0,-38,-22,2" ItemsSource="{Binding Items}" SelectionChanged="LongListSelector_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="12,2,0,4" Height="110" Width="432">
<StackPanel Width="311" Margin="0,0,0,0">
<TextBlock Text="{Binding LineOne}" TextWrapping="Wrap" Margin="10,0" Style="{StaticResource PhoneTextExtraLargeStyle}" FontSize="{StaticResource PhoneFontSizeLarge}" />
<TextBlock Text="{Binding LineTwo}" TextWrapping="Wrap" Margin="10,-2,10,0" Style="{StaticResource PhoneTextSubtleStyle}" />
</StackPanel>
<StackPanel Name="playImage" Height="50" Width="50" Margin="0,0,10,0">
<Image Source="Assets/Tiles/Iconsmind-Outline-Play-Music.ico" Visibility="{Binding ImageVis}" Width="50" Height="50" HorizontalAlignment="Left" Tap="Image_Tap_1"/>
</StackPanel>
<StackPanel Name="downloadImage" Height="50" Width="50" Margin="0,0,0,0">
<Image Source="Assets/Tiles/Download.ico" Visibility="{Binding ImageVis}" Width="50" Height="50" HorizontalAlignment="Left" Tap="Image_Tap_1"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
</phone:PanoramaItem>
selection changed event:
private void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ItemViewModel item = new ItemViewModel();
item.ImageVis = Visibility.Visible;
//it can't be called the way you are doing it of course and it still doesn't work
}
ViewModel
private Visibility _imageVis;
public Visibility ImageVis
{
get { return _imageVis; }
set
{
_imageVis = value;
NotifyPropertyChanged("ImageVis");
}
}
Create a property of type Visibility an bind it to your image visibility.
ViewModel:
private Visibility _DownloadImage;
public Visibility DownloadImage
{
get { return _DownloadImage; }
set
{
if (_DownloadImage != value)
{
_DownloadImage = DownloadImage;
OnPropertyChanged("DownloadImage");
}
}
}
xaml
<Image Source="Assets/Tiles/Download.ico" Visibility="{Binding DownloadImage}" ... />
xaml.cs (I would prefer to bind the command also to the ViewModel, to keep the MVVM pattern)
private void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DownloadImage = Visibility.Visible;
}

Bind NavigateUri property of HyperlinkButton Windows Phone 8

I am parsing some JSON data using Newtonsoft.NET for my WP8 app in C#/XAML and everything works fine except the binding of NavigationUri to the HyperlinkButton. Here is the DataTemplate of my databound LongListSelector:
<DataTemplate>
<StackPanel Margin="10 10 10 20" Background="{StaticResource PhoneAccentBrush}">
<TextBlock Text="{Binding MovieTitle }" TextWrapping="Wrap" FontSize="18" />
<TextBlock Text="{Binding ImdbCode }" TextWrapping="Wrap" FontSize="18" />
<HyperlinkButton NavigateUri="{Binding ImdbLink}">View on IMDB</HyperlinkButton>
<Image Source="{Binding MovieCover}" Width="300" Height="300" HorizontalAlignment="Center"/>
<TextBlock Text="{Binding ImdbLink}" TextWrapping="Wrap" FontSize="18" />
</StackPanel>
</DataTemplate>
This way everything is loaded correctly but the HyperLinkButton doesn't navigate to the Uri.
What should I do to make sure the navigation works?
If it is not possible with HyperLinkButton then can I add a regular button to which I could pass the url so that OnClick event can navigate to url.
Assuming the url is correct the webbrowser can be activated like this:
XAML
<HyperlinkButton NavigateUri="{Binding ImdbLink}"
Click="NavigateButton_Click">View on IMDB</HyperlinkButton>
C#
private void NavigateButton_Click(object sender, RoutedEventArgs e)
{
var hyperlinkButton = sender as HyperlinkButton;
if(hyperlinkButton == null)
{
return;
}
ShowInBrowser(hyperlinkButton.NavigateUri);
}
private void ShowInBrowser(Uri url)
{
Microsoft.Phone.Tasks.WebBrowserTask wbt =
new Microsoft.Phone.Tasks.WebBrowserTask();
wbt.Uri = url;
wbt.Show();
}
This is because you have no RequestNavigate method. Try:
<HyperlinkButton NavigateUri="{Binding ImdbLink}" RequestNavigate="Hyperlink_RequestNavigate">View on IMDB</HyperlinkButton>
and in your code behind for the view put
private void Hyperlink_RequestNavigate(object sender, RequestNavigateEventArgs e)
{
Process.Start(new ProcessStartInfo(e.Uri.AbsoluteUri));
e.Handled = true;
}
or however you want to deal with that click event (i.e. open a new webview with that as the url)

How to get text from TextBox inside ListViewItem's DataTemplate

I don't know how to get text from "firstBox" and "secondBox" after button click.
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<!-- some code -->
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding Data}" VerticalAlignment="Top" Height="18" Width="100" FontSize="13.333" Margin="162,9,0,0"/>
<TextBlock HorizontalAlignment="Left" Margin="0,35,0,0" TextWrapping="Wrap" Text="{Binding D_gospodarzy}" FontSize="14.667" VerticalAlignment="Top" Height="59" Width="100"/>
<TextBlock HorizontalAlignment="Center" Margin="268,35,7,0" TextWrapping="Wrap" Text="{Binding D_gosci}" FontSize="14.667" VerticalAlignment="Top" Width="100" Height="59"/>
<TextBox x:Name="firstBox" ... />
<Button Content="Click" " Click="Button_Click_1"/>
<TextBox x:Name="secondBox" ... />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
I get only the object
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var myobject = (sender as Button).DataContext;
}
There are cuple of ways to do it, for example you can traverse the VisualTree of clicked button's parent and retrive TextBox with the name you want. In this case, I would take advantage of an extension method written by yasen in this answer.
Then it can look for example like this:
private void Button_Click_1(object sender, RoutedEventArgs e)
{
var parent = (sender as Button).Parent;
TextBox firstOne = parent.GetChildrenOfType<TextBox>().First(x => x.Name == "firstBox");
Debug.WriteLine(firstOne.Text);
}
Remember to put an extension method somewhere in a static class:
public static class Extensions
{
public static IEnumerable<T> GetChildrenOfType<T>(this DependencyObject start) where T : class
{
// rest of the code
Here's how to get the text..
String text1 = firstBox.Text;
String text2 = secondBox.Text;
note: firstBox and secondBox must be class members to use them in different class methods.

How to select an item in a ListBox and pick the item's name from a DataTemplate in WPF

I am implementing a Download UI in WPF, where every file that is being downloaded will be shown inside a list box in a DataTemplate
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="FileName" text={Binding FileName}" />
<ProgressBar ... />
<Button Content="Cancel" click="ButtonCancel_Click" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox>
Now this List is getting populated with all the download information perfectly. Only problem I am having is that when user clicks on Cancel button, to cancel the download, I have to remove an entry from the ObservableCollections. But I don't have the File Name in the click event( I know click event is not MVVM, still I want to do it in click event handler).
Can anyone suggest how do I get the FileName of that particular file when the selectedItem gets cancelled. in The
private void ButtonCancel_Click(...) {}
Although I would still encourage you to use MVVM way of dealing with UI events, here's how you can achieve what you want, using Cancel button's click event handler.
First in your xaml, bind file name to Cancel button's Tag property.
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock x:Name="FileName" text={Binding FileName}" />
<ProgressBar ... />
<Button Content="Cancel" Tag="{Binding FileName}"
Click="ButtonCancel_Click" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox>
Then in your click event handler
private void ButtonCancel_Click(object sender, RoutedEventArgs e)
{
Button myButton = (Button)sender;
string fileName = myButton.Tag.ToString();
// use fileName
}
Edit
Just to add a complete example, that was tested locally, and ensured that works.
XAML
<Window x:Class="WpfTestApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox Name="listBox1">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock x:Name="FileName" Text="{Binding Path=FileName}" />
<Button Content="Cancel" Tag="{Binding Path=FileName}"
Click="ButtonCancel_Click" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Code-behind
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var fileNames = new List<DownloadModel>
{
new DownloadModel
{
FileName = "File1"
},
new DownloadModel
{
FileName = "File2"
},
new DownloadModel
{
FileName = "File3"
}
};
listBox1.ItemsSource = fileNames;
}
private void ButtonCancel_Click(object sender, RoutedEventArgs e)
{
var myButton = sender as Button;
if (myButton.Tag == null)
{
MessageBox.Show("Tag value was null.");
}
else
{
MessageBox.Show(string.Format("File name is {0}", myButton.Tag));
}
}
}
public class DownloadModel
{
public string FileName { get; set; }
}

Categories