Okay, What I'm trying to accomplish:
A tabheader which gets an image if the textbox inside has text. but if the textbox inside the TabItem doesn't have any text, then the image should not be shown.
this is what I have so far:
----- TAB ITEM CODE -----
<TabItem Name="tabAantekeningen" Header="">
<TabItem.HeaderTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="8" Text="Aantekeningen"/>
<Image Grid.Column="1" Source="..\Resources\validate.png" Height="20" Width="17"/>
</Grid>
</DataTemplate>
</TabItem.HeaderTemplate>
<TextBox Name="txtOmschrijving" TextWrapping="Wrap" AcceptsReturn="True"></TextBox>
</TabItem>
----- TAB ITEM CODE -----
----- Code Behind -----
public void SetTabItemHeader()
{
if (String.IsNullOrEmpty(txtOmschrijving.Text))
{
tabAantekeningen.Header = "Aantekeningen";
}
}
----- Code Behind -----
IS there a way that I can say: txtOmschrijving.Text == Empty so hide the Image?
Edit: Didn't see your seccond question there, yes there is use a IValueConverter, where you check if the string is empty and Bind To Visibility for instance, so you return Visbility.Collapsed when empty or else Visbility.Visible.
Like this :
public class StringEmptyToVisbililityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (value == null) || !(value is string) || string.IsNullOrEmpty(value.ToString()) ? Visibility.Collapsed : Visibility.Visible;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Fully working xaml, change your namespaces and URI pack
<Window x:Class="TabItemHeader.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TabItemHeader"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:StringEmptyToVisbililityConverter x:Key="StringEmptyToVisbililityConverter"/>
</Window.Resources>
<Grid>
<TabControl>
<TabItem Name="tabAantekeningen">
<TabItem.HeaderTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="8" Text="{Binding Path='Header',RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem}}}"/>
<Image Grid.Column="1" Source="pack://application:,,,/TabItemHeader;component/Resources/Images/validate.png" Height="20" Width="17" Visibility="{Binding Path='Header', Converter={StaticResource StringEmptyToVisbililityConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem}}}"/>
</Grid>
</DataTemplate>
</TabItem.HeaderTemplate>
<TextBox Name="txtOmschrijving" TextWrapping="Wrap" AcceptsReturn="True"></TextBox>
</TabItem>
</TabControl>
</Grid>
This will bind to the listboxitem which wraps everything in a listbox. The converter will only show this image when the string is not empty. You can do alot of fun with them :)
WPF cheat sheet is a really handy and compact paper on all types of bindings.
Oh..I am assuming this image will be deployed with your application? Then please ensure that your image is set to resource, you should consider using uri packs as well for your images, an example is in this post as well as the xaml provided. If your image is dynamic, you will have to bind them to some model in an observablecollection.
Tip: I'll stop pushing this to far, but you should consider having a look at the MVVM pattern. I just used code behind my self, so the answer wouldn't get to big. It's whole other topic! =) There are also cleaner ways to either share templates, and change them on types bound in the collection.
Hope it helps.
Cheers,
Stian
Related
I have a "master frame" (which contains only the CommandBar) and some child frames, which are initially in a hub. Basically the frame changes, when one hub element is clicked on via "OnNavigated.."
Now I have some buttons (for example 1 and 2) which should not be visible, only when certain frames are chosen:
I've tried it with getter and setter methods:
In the Master-Frame code-methods:
public static Visibility setVisibility
{
set { Button1.Visibility = value; }
}
and in the Frame1 code behind:
MasterFrame.setVisibility = Visibility.Visible;
But I'm getting the error from Button1 "An object reference is...", because I have to use the "static" modifier to get access to the button from Frame1.
How can I get access to the button?
I don't even know if I'm using the "right" approach with the code-behind, but the MVVM seems to be not useful, as this isn't a CRUD-application (simple information without user-input.)
I don't even know if I'm using the "right" approach with the code-behind, but the MVVM seems to be not useful, as this isn't a CRUD-application (simple information without user-input.)
No, MVVM is useful, in the MVVM design pattern, developers can code app logic, and designers can create the UI. Although you're not developing a CRUD-application, MVVM pattern can still be used.
In a UWP app, Data Binding is very powerful. In this case, you can use data binding together with Converter to solve your problem.
I wrote a sample here to use Data Binding for event, and use Converter to judge the Visibility of Button and AppBarButtons:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.Resources>
<Converter:VisiableOrNot x:Key="cvt" />
<Converter:NaviButtonShowOrNot x:Key="btncvt" />
</Grid.Resources>
<CommandBar>
<CommandBar.Content>
<Grid>
<TextBlock Text="Master-Frame" FontSize="20" Margin="20,10" />
</Grid>
</CommandBar.Content>
<AppBarButton Icon="Accept" Label="appbarbutton" Visibility="{Binding ElementName=mainPageframe, Path=Content.BaseUri.AbsoluteUri, Converter={StaticResource cvt}}" />
<AppBarButton Icon="Cancel" Label="appbarbutton" Visibility="{Binding ElementName=mainPageframe, Path=Content.BaseUri.AbsoluteUri, Converter={StaticResource cvt}}" />
</CommandBar>
<Frame x:Name="mainPageframe" Margin="0,55">
<Hub x:Name="hub" SectionHeaderClick="{x:Bind MainPageViewModel.hub_SectionHeaderClick}">
<HubSection x:Name="image1" Header="Image1" Width="200" IsHeaderInteractive="True">
<DataTemplate>
<Grid>
<Image Source="Assets/111.png" Stretch="None" />
</Grid>
</DataTemplate>
</HubSection>
<HubSection x:Name="image2" Header="Image2" Width="200" IsHeaderInteractive="True">
<DataTemplate>
<Grid>
<Image Grid.Row="0" Source="Assets/222.png" Stretch="None" />
</Grid>
</DataTemplate>
</HubSection>
<HubSection x:Name="image3" Header="Image3" Width="200" IsHeaderInteractive="True">
<DataTemplate>
<Grid>
<Image Source="Assets/333.png" Stretch="None" />
</Grid>
</DataTemplate>
</HubSection>
</Hub>
</Frame>
<Button Content="Go Back" Click="{x:Bind MainPageViewModel.Button_Click}" Background="PaleGreen" VerticalAlignment="Bottom" Margin="50,20" Visibility="{Binding ElementName=mainPageframe, Path=Content.BaseUri.AbsoluteUri, Converter={StaticResource btncvt}}" />
</Grid>
Code of VisiableOrNot converter:
public class VisiableOrNot : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
Uri uri = new Uri(value.ToString());
if (uri != null)
{
if (uri.Equals("ms-appx:///View/Page3.xaml"))
{
return Visibility.Visible;
}
}
return Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
Here is the rendering image of my demo, the AppBarButtons can be seen only when the child frame's content is Page3. And the navigate back button can not be seen when it is on MainPage:
Here is my demo, you can download it and have a check.
To hide a ui element just do this:
this.MyComponent.Visibility = Visibility.Collapsed;
And to make it visible do this:
this.MyComponent.Visibility = Visibility.Visible;
I have a ListView in a FlipView
<FlipView
x:Name="flipView"
AutomationProperties.AutomationId="ItemsFlipView"
AutomationProperties.Name="Item Details"
TabIndex="1"
Width="Auto"
Grid.Row="2"
Grid.Column="1"
VerticalAlignment="Top"
HorizontalAlignment="Center"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}" Padding="0" VirtualizingStackPanel.VirtualizationMode="Standard">
<FlipView.ItemTemplate>
<DataTemplate>
<!--
UserControl chosen as the templated item because it supports visual state management
Loaded/unloaded events explicitly subscribe to view state updates from the page
-->
<UserControl Loaded="StartLayoutUpdates" Unloaded="StopLayoutUpdates">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="1" Orientation="Vertical" Margin="0,100,0,0">
<ListView x:Name="ListofOptions" Height="400" Width="280"
ItemsSource="{Binding QuestionOptions}" SelectedValue="{Binding Answer,Mode=TwoWay}"
IsEnabled="{Binding IsEnabled,Mode=TwoWay}" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<StackPanel.Resources>
<common:AltBackgroundConverter x:Key="BGConvertor" />
</StackPanel.Resources>
<StackPanel.Background>
<SolidColorBrush Color="{Binding IndexWithinParentCollection, Mode=OneWay, Converter={StaticResource BGConvertor}}"></SolidColorBrush>
</StackPanel.Background>
<TextBlock Text="{Binding OptionValue}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</Grid>
</UserControl>
</DataTemplate>
</FlipView.ItemTemplate>
</FlipView>
I write a value conventor of ListView for changing background of alternative row. here is Conventor's code
public class AltBackgroundConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
if (!(value is int)) return null;
int index = (int)value;
if (index % 2 == 0)
return Colors.White;
else
return Colors.LightGray;
}
// No need to implement converting back on a one-way binding
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
throw new NotImplementedException();
}
}
when the listbox is out of FlipView everything is Ok but the Conventor doesn't execute when the ListView is in a FlipView. please advice me.
Created a new Split XAML project in VS2012 and added your converter there and used it in ListView and it was still working after moving the ListView inside a FlipView.
I'm now guessing it's a binding issue, happening because root binding object has changed and one of the bindings not resolved as we expect. have you tried moving the Resources tag to upper level which is the FlipeView?
P.S. This is more of a comment, but I don't have reputation for comments!
I've created a listbox, to which i can add and delete items dynamically UI changes accordingly and it works fine.
<ListBox Name="MsgsList" ItemsSource="{Binding Items}" Style="{StaticResource MsgsBoxStyle}">
<ListBox.ItemTemplate>
<DataTemplate x:Name="MsgsDataTemplate">
<StackPanel Tag="{Binding MsgTagInfo}" ManipulationCompleted="StackPanel_Msgs_ManipulationCompleted">
<toolkit:GestureService.GestureListener>
<toolkit:GestureListener Hold="GestureListener_Hold" Tap="GestureListener_Tap"/>
</toolkit:GestureService.GestureListener>
<Grid x:Name="ContentPanelInner" Grid.Row="1" Width="500">
<StackPanel x:Name="stackPanelInner" Width="500">
<Grid VerticalAlignment="Top" Width="500">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding MsgTitle}" Style="{StaticResource MsgLine1}" />
<TextBlock Grid.Column="1" Text="{Binding MsgDate}" Style="{StaticResource MsgDate}" />
</Grid>
<TextBlock Text="{Binding MsgBody}" Style="{StaticResource MsgLine2}" />
</StackPanel>
</Grid>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
but i didn't understand how to change a style for a particular item's textblock, say based on some condition, if i want to change color of specific item's textbox(s), not sure how to access that.
can somebody please help me with this? thanks.
Probably not the easiest way to do this, but arguably the cleanest from a separation of concerns point of view is by using a converter, and binding that to the property you want to monitor...
For example, if your model is changing state based on a boolean property called myProperty, you could use something like this.
<StackPanel Background={Binding myProperty, Converter={StaticResource myBindingConverter}" />
Your converter should return a SolidColorBrush, based on the value of your property.
public class AlternateRowColour : IValueConverter
{
SolidColorBrush normal = new SolidColorBrush(Colors.Transparent);
SolidColorBrush highlighted = new SolidColorBrush(Color.FromArgb(255, 241, 241, 241));
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var myValue = (bool)value
return myValue ? highlighted : normal ;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
I If you just want to change on aspect of an items style, for example its color, you could expose that as property of the model object you are binding. For example, add a property TextColor and bind it as follows:
<TextBlock Text="{Binding MsgBody}" Style="{StaticResource MsgLine2}">
<TextBlock.Color>
<SolidColorBrush Color="{Binding TextColor}"/>
</TextBlock.Color>
</TextBlock>
This will take precedence over the colour defined via the style.
I have this pretty simple window with a Grid containing two columns, a TextBlock and a TextBox.
What I need it to set the column 0 to automatically size to its content and to have column 1 (content) to be 4 times the size of the column 0.
How can I do that. I will create a Grid descendant if this is the solution because I really need this feature.
Edit: more explanations. The content of the column 0 won't change at runtime so the size of the column 0 or column 1 must not change on runtime. The grid will be the child of a window configured with SizeToContent="WidthAndHeight" so no extra space must exist.
Answer to Dmitry: I tried what you say with the following code and it is not working at all:
<Window x:Class="UnderstandSizing.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1"
SizeToContent="WidthAndHeight" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".25*" />
<ColumnDefinition Width=".75*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Text="THIS IS THE LABEL:" />
<TextBox Grid.Column="1" Text="content" />
</Grid>
</Window>
Last Edit: Why the hell do I (or anyone) need this?
One of the nice things of WPF is its hability to work without fixed sizes right? If you are impaired and you have a bigger font size everything will look fine. If you translate your UI to another language that needs x2 size everything will look fine. If you have different PPI settings everything will look fine.
But what I don't want to see is screens changing its size at runtime because users are not used to this. That's why I want to set the size of the entry fields to a multiple of a know field. If I let the label cell to re size to what it needs and then I set the content cell to a multiplier of the label I will get the benefits of autosizing with the behaviour that users expect of having fixed size screens (unless they change it resizing it).
You can use bindings on grid columns:
<Grid.ColumnDefinitions>
<ColmunDefinition Width="Auto" x:Name="firstCol"/>
<ColumnDefinition Width="{Binding ActualWidth, ElementName=firstCol, Converter={StaticResource MultiplyConverter}, ConverterParameter=4}" />
</Grid.ColumnDefinitions>
Then the converter:
public class MultiplyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double originalValue;
double multiplier;
if (value != null && parameter != null &&
double.TryParse(value.ToString(), out originalValue) &&
double.TryParse(parameter.ToString(), out multiplier)) //Can be lots of things: sentinel object, NaN (not a number)...
{
return originalValue * multiplier;
}
else return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
You could write an attached property for grid columns also.
Edit:
If the sizes are known at compile time, wouldn't it be easier to set the widths manually?
You could use a BindingConverter for that, I'd go with separate items in a horizontal StackPanel (look that the StackPanel's width is big enough for your contents):
Here's the cleaned code.
MainWindow.xaml:
<!-- define xmlns:local="clr-namespace:YourAppNamespace" -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<StackPanel.Resources>
<local:WidthConverter x:Key="wc" />
</StackPanel.Resources>
<Grid Background="Gray" x:Name="col1">
<TextBlock Text="blub"/>
</Grid>
<Grid Background="Orange" Width="{Binding ElementName=col1, Path=ActualWidth, Converter={StaticResource ResourceKey=wc}}">
<Label Content="bla"></Label>
</Grid>
</StackPanel>
MainWindow.xaml.cs:
public class WidthConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (!(value is double))
{
return Binding.DoNothing;
}
return ((double)value) * 4.0;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
Taken from: http://www.tanguay.info/web/index.php?pg=codeExamples&id=36
the idea is to use:
Update 2 - full XAML posted (mind the behavior of your grid's children):
<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="350" Width="525">
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".25*" />
<ColumnDefinition Width=".75*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid Background="Yellow" Grid.Column="0">
<TextBlock Text="THIS IS THE LABEL:" />
</Grid>
<Grid Background="Blue" Grid.Column="1">
<TextBox Background="Transparent" Text="content" />
</Grid>
</Grid>
</Grid>
</Window>
I've just checked it and it worked.
Update: Simply put - there's no out of the box way for doing this in WPF. Depending on your circumstanes you'll have to come up with some sort of a trick to get your grid working.
Another problem is - in general WPF layouts are designed to be protective, i.e. if your grid's child cannot be shrinked down - normally your layout logic should accomodate for it, typically by suspending some layout rules.
As I understand you are trying to layout the label (textblock) and the corresponding entry field for it. As an indicator, you should first see the Beth Massi's Windows Client video on simple data entry form which is on developing a data entry form but laying out is also demonstrated very well.
Particularly observe how she lays out the controls on the WPF Window using the designer, properties window and XAML, and then I think you should not have a need for the first column to be of Auto size and second column of 4* first column.
EDIT: As per update in question, I am posting a possible solution as below:
XAML file code (Notice the SizeToContent usage in Window and that the binding is to ActualWidth property for Textbox control):
<Window x:Class="GridTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:GridTest"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
d:DesignHeight="350"
d:DesignWidth="525"
SizeToContent="WidthAndHeight"
mc:Ignorable="d">
<Grid>
<Grid.Resources>
<local:FourWidthConverter x:Key="FourWidthConv" />
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Name="tb"
Grid.Column="0"
Text="Auto Text, change at design time to see changes in Width" />
<TextBox Name="tx"
Grid.Column="1"
Width="{Binding ElementName=tb,
Path=ActualWidth,
Converter={StaticResource FourWidthConv}}"
Text="4 * col 1 width displaying Text in SizetoContentWindow" />
</Grid>
</Window>
.Xaml.cs file code (Notice the converter here):
using System.Windows;
using System.Windows.Data;
namespace GridTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
public class FourWidthConverter : IValueConverter
{
public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return 4 * (double)value;
}
public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new System.NotImplementedException();
}
}
}
I have a ListBox with a DataTemplate. The template has a Button on it. When the Button is clicked I want to do some logic with the object that is each row (in this case an object called WorkItemTypeMappings).
In theOnClick how can I go from the Button (object sender) to the object that is row that the button is on?
Here is the XAML of my ListBox:
<ListBox ItemsSource="{Binding Source={StaticResource WorkItemTypeMappingsCollectionView}}" HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Name="lstWITypes">
<ListBox.GroupStyle>
<x:Static Member="GroupStyle.Default"/>
</ListBox.GroupStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{Binding SourceType, Converter={StaticResource WorkItemTypeToStringConverter}}"/>
<ComboBox Grid.Column="1" SelectedItem="{Binding DestType}" ItemsSource="{Binding WorkItemTypesForCurrentDestProject, Source={x:Static loc:MainMediator.Instance}, diagnostics:PresentationTraceSources.TraceLevel=High}" DisplayMemberPath="Name" />
<!-- This is the button-->
<Button Grid.Column="2" Content="{Binding PercentMapped}"
Click="ManualMappingClick"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What you can do as an alternative is to use Command instead of Event. If you bind your button to a command and pass along with it a command parameter, you should be able to get the item that is related to that button. Example code:
<!-- This is the button-->
<Button
Grid.Column="2"
Content="{Binding PercentMapped}"
Command="SolutionNamespace:CommandClass.ButtonClickedCommand"
CommandParameter="{Binding}" />
I am not sure how familiar you are with WPF commanding but you will notice that the CommandParameter binds to the context without a path name, that is to say it binds to the WorkItemTypeMappings that you need.
Command Example Code:
public static SimpleCommand ButtonClickedCommand { get; set; }
static CommandClass()
{
ButtonClickedCommand = new SimpleCommand
{
ExecuteDelegate =
x=> ButtonClicked(x as WorkItemTypeMappings)
};
}
public static ButtonClicked(WorkItemTypeMappings mappings)
{
if(mappings != null) MessageBox.Show(mapping.PercentMapped)
}
You will notice that the ButtonClickedCommand is static, this is required because the button cannot access the command from its current binding context.
SimpleCommand is just a simplified implementation of the ICommand, can Google this one if you're not sure. I hope this is not an overkill to your problem, but you cannot go wrong with WPF Commands.
Good luck.
Try using VisualTreeHelper to find the parent ListBoxItem for the button. A few good general all-purpose helper functions can be found here:
How can I find WPF controls by name or type?
so, for example, you could find the ListBoxItem from the click event with a call like this:
ListBoxItem item = UIHelper.FindVisualParent<ListBoxItem>(sender);
have you tried ListBox.SelectedItem?
Additionally, if you have a reference to the ListBoxControl already, and you also have the data item representing the row (I assume so since you have the binding, and thus can drag it out of the DataContext on the button), you can ask the ItemsContainerGenerator. ContainerFromItem to give you give you the actual UIElement for the row.
The itemcontainergenerator can be found as a property on the listview itself. (technically the itemscontrol, since thats where it's defined)