Image binding two way mode not working wpf c# - c#

i have an image tag in my window, whenever i am binding it in one way mode, its working fine, but unable to two way mode.
<ComboBox Grid.Column="1" DisplayMemberPath="sm.admno" Grid.Row="0" Name="txtadm" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" IsEditable="True"/>
<Image Grid.Column="6" Grid.Row="0" Source="{Binding ElementName=txtadm, Mode=TwoWay, Path=SelectedItem.sp.pic, UpdateSourceTrigger=PropertyChanged}" Grid.RowSpan="4" Grid.ColumnSpan="2" Name="imgpic"/>
class i am using
public string admno { get; set; }
public byte[] pic { get; set; }
data binding souce
var dt = from sm in db.studentmains
join sp in db.StudentPersonals on sm.admno equals sp.admno
select new { sm, sp};
txtadm.ItemsSource = dt.ToList();

Image.Source is not a property for which TwoWay makes any sense, the control is not interactive, it's not going to change the source. If you modify it, you should modify the data, not the Image.Source.

Related

C# UWP Button binding with flyout not refreshing button content

I have a button that displays the value from a class that I created. Everything works fine, except for the fact that the button content does not refresh once the value of the binding is changed in the code. If I exit the screen and come back, the value is correct. Staying on the same screen does not refresh the button content.
The button code is shown below.
<Grid x:Name="Task1Grid" Grid.Row="0" Grid.Column="0" Margin="5,0,5,0">
<Grid.RowDefinitions>
<RowDefinition Height=".2*"/>
<RowDefinition Height=".6*"/>
<RowDefinition Height=".2*"/>
</Grid.RowDefinitions>
<Button Grid.Row="1" Style="{StaticResource RoundedButtonStyle}" Tag="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Click="StoplightButton_Click" FontFamily="Global User Interface">
<Button.Content>
<Image Stretch="Uniform" Source="{Binding SelectedRepairOrder.TaskStatusGrid[0], Converter={StaticResource TaskStatusToStopLight}, Mode=OneWay}"/>
</Button.Content>
<Button.Background>
<ImageBrush Stretch="Uniform" ImageSource="{Binding SelectedRepairOrder.TaskStatusGrid[0], Converter={StaticResource TaskStatusToStopLight}, Mode=OneWay}"/>
</Button.Background>
</Button>
<Button x:Name="Task0Time" Tag="0" Style="{StaticResource RoundedButtonStyle}" Visibility="{Binding SelectedRepairOrder.TaskStatusGrid[0].NewTaskstatus, Converter=
{StaticResource TaskStatusToVisibility}}" IsEnabled="{Binding ShowForecastFeatures}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="{Binding SelectedRepairOrder.TaskStatusGrid[0].TmTimecmpltask, Converter={StaticResource TaskCompleteTimeToTime}}" Grid.Row="2" Flyout="{StaticResource Task1Flyout}"/>
<TextBlock Grid.Row="0" Text="{Binding ClientInfo.TasksInfo[0].TaskDescription}" TextAlignment="Center" VerticalAlignment="Bottom" FontSize="28"/>
</Grid>
The flyout code is shown below.
<Border x:Name="StopLightBorder" Background="CornflowerBlue" Grid.Row="1" BorderBrush="White" BorderThickness="2">
<Grid x:Name="StopLightGrid" Margin="5" >
<Grid.Resources>
<converter:TaskStatusToStopLight x:Key="TaskStatusToStopLight"/>
<converter:TaskCompleteTimeToTime x:Key="TaskCompleteTimeToTime"/>
<converter:TaskStatusToVisibility x:Key="TaskStatusToVisibility"/>
<Flyout x:Key="Task1Flyout" >
<ListBox ItemsSource="{Binding ForecastTimes}" Tag="0" SelectionChanged="ForecastTimeChanged"/>
</Flyout>
The code which changes the value for the binding is shown below.
private void ForecastTimeChanged(object sender, SelectionChangedEventArgs e)
{
var timeListBox = (ListBox)sender;
var completeTime = Convert.ToDateTime(e.AddedItems[0].ToString());
var taskNum = Convert.ToInt16(((FrameworkElement)sender).Tag);
var result = checkPreviousTaskTimes(completeTime, taskNum);
switch (result)
{
case ForecastResult.ValidTime:
globalContext.SelectedRepairOrder.TaskStatusGrid[taskNum].TmTimecmpltask = completeTime.ToString();
globalContext.SelectedRepairOrder.TaskStatusGrid[taskNum].DtDateoverride = completeTime.ToString();
globalContext.SelectedRepairOrder.TaskStatusGrid[taskNum].TmTimeoverride = completeTime.ToString();
globalContext.SelectedRepairOrder.TaskStatusGrid[taskNum].SendOverrideForecastTime = true;
globalContext.SelectedRepairOrder.WasChanged = true;
globalContext.SelectedRepairOrder.RecordGrid = "1";
((Popup)((FlyoutPresenter)((FrameworkElement)sender).Parent).Parent).IsOpen = false;
break;
default:
showForecastError(result, completeTime, taskNum);
break;
}
}
The Visibility and IsEnabled both work just fine. Not sure what else I can do at this point. It seems that changing the bound data does not have an effect until you leave the screen. I chased this issue all the way through and saw the changes to the data as well as everything else I expected. The flyout causes the forecasttimechanged method to activate. When we go to save this data to the database, the data is correct. The flyout shows the selected time when viewing it on the screen, which is what I want. I see that highlighted in the flyout.
If there is a better control to use than the button, I am all ears at this point. Here is the tricky part. This forecast time can be set in the application as well as the app you are seeing code from. The app has time in 15 minute increments, but the other program that can update this control can put in any time it wishes.
I know there is some control or parameter that needs to be set in order to make this happen properly, but for the life of me, I cannot find it. I have tried everything for the past 3 days now and nothing works.
Help me please.
I know there is some control or parameter that needs to be set in order to make this happen properly, but for the life of me, I cannot find it. I have tried everything for the past 3 days now and nothing works.
From your code, I guess the problem is that you have not implemented INotifyPropertyChanged for binding property. And your logic is complex, you could realize your feature with the easy way like the follow example.
<Button Content="{Binding SelectItem,Mode=OneWay}">
<Button.Flyout>
<Flyout Placement="Top">
<ListBox ItemsSource="{Binding Items}" SelectedItem="{Binding SelectItem,Mode=TwoWay}">
</ListBox>
</Flyout>
</Button.Flyout>
</Button>
Bind the button content with SelectItem, And then the button content will be modified automatically if the ListBox SelectedItem changed.
public class MainPageViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public List<string> Items { get; set; } = new List<string>();
private string selectItem = "Nico";
public string SelectItem { get { return selectItem; } set { selectItem = value; OnPropertyChanged(); } }
public MainPageViewModel()
{
Items.Add("Nico");
Items.Add("Song");
Items.Add("Xiao");
}

Accessing TextBox Text Inside GridView (C# / XAML)

So I have a customised GridView with a data template that contains a TextBox and is populated by a list of a custom class called Player. I need to be able to retrieve both the instance of Player and the text in the TextBox and save them to a new custom class called Score.
<GridView x:Name="gridScore" ItemsSource="{x:Bind PlayerList}" IsItemClickEnabled="True">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:Player">
<StackPanel Orientation="Horizontal">
<TextBox x:Name="txtbxGridScore" TextChanged="txtbxGridScoreChangedEventHandler" />
<Image Source="{x:Bind ProfilePicture}"/>
<StackPanel VerticalAlignment="Center">
<TextBlock Text="{x:Bind FullName}" />
<TextBlock Text="{x:Bind Alias}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
<Button x:Name="buttonSave" Content="Save Scores" Style="{StaticResource BarButtonStyle}" Click="buttonSave_Click"/>
I come from a web-based Java background so this is a little bit new to me but it seems like it should be a fairly simple exercise.
Initially, I tried iterating through the GridView upon a Button Click and grabbing each Player item along with the TextBox Text and saving them to a List<> of Score, however, getting the TextBox value proved troublesome.
I then tried initialising a page scope List<> of Score and simply updating it each time the TextBox value was changed, however, I wasn't able to make this work either.
A solution for either approach will work fine for my purposes. Any input is appreciated!
If I correctly understood you this is one of the way to resolve your problem.
So let's assume that your model class Player have this structure:
public class Player {
public int PlayerID { get; set; }
public string ProfilePicture { get; set; }
public string FullName { get; set; }
public string Alias { get; set; }
public float PlayerScore { get; set; } // To store textbox value
}
So you can resolve this by using two way binding.
XAML part will look something like this:
<GridView x:Name="gridScore"
ItemsSource="{x:Bind PlayerList}"
IsItemClickEnabled="True">
<GridView.ItemTemplate>
<DataTemplate x:DataType="data:Player">
<StackPanel Orientation="Horizontal">
<TextBox x:Name="txtbxGridScore"
Text="{x:Bind PlayerScore, Mode=TwoWay}" />
<Image Source="{x:Bind ProfilePicture}" />
<StackPanel VerticalAlignment="Center">
<TextBlock Text="{x:Bind FullName}" />
<TextBlock Text="{x:Bind Alias}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
<Button x:Name="buttonSave"
Content="Save Scores"
Click="buttonSave_Click" />
I have initialized your PlayerList with some dummy data like this:
PlayerList = new ObservableCollection<Player>() {
new Player() {
FullName = "Player A", Alias = "AAA"
},
new Player () {
FullName = "Player B", Alias = "BBB"
}
};
As you can see in XAML I am binding your text box with PlayerScore property of Player model.
When I run this App I get screen like this:
I will input some data into TextBox and click Save button:
When I click on Save it will trigger the event that you wrote in Button part
In that event I have one foreach loop that will iterate through the list and one breakpoint and as you can see on first item "Player A" the PlayerScore value is 10:
Now you can find your players with some ID property or with some other way that you want. This is the most simple way to accomplish what you want.
Remark: This could be solved in a better way using MVVM pattern and other stuff but as you mentioned you are beginner so maybe it is better for you to solve it like this and after that go with more advanced technique. Hope that this was helpful for you.

How to display individual item names in a WPF ListBox using Data Binding?

In my WPF application, I have a ListBox in my main screen. I'm trying to use the MVVM pattern, so I have a ViewModel associated with the View. When I launch the application, my ViewModel gets initiated, and it reads in a bunch of DLLs I've placed in a directory. Each DLL contains a "Strategy" class, so when I read the DLLs, I retrieve these Strategy class objects and put them in a list (actually an ObservableCollection) which is a member of my ViewModel. I'm using this member list, named DllList, to populate the ListBox.
My ViewModel looks like the following (unnecessary bits removed for clarity):
public class ViewModelPDMain : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged(string propertyName) {
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public ViewModelPDMain() {
dllList = new ObservableCollection<Strategy>();
selectedStrategy = new Strategy();
}
private ObservableCollection<Strategy> dllList = null;
private Strategy selectedStrategy = null;
public ObservableCollection<Strategy> DllList
{
get { return dllList; }
set {
dllList = value;
RaisePropertyChanged("DllList");
}
}
public Strategy SelectedStrategy
{
get { return selectedStrategy; }
set {
selectedStrategy = value;
RaisePropertyChanged("SelectedStrategy");
}
}
}
Then in my main View, I bind it as follows.
<Window x:Class="PrisonersDilemma.Source.View.ViewPDMain"
xmlns:local="clr-namespace:PrisonersDilemma.Source.View"
DataContext="{Binding Source={StaticResource mainViewModelLocator}, Path=ViewModelPDMain}"
Title="Iterated Prisoner's Dilemma" Height="500" Width="800" MinHeight="500" MinWidth="800">
<Grid Name="gridMain">
...
<!-- More stuff here -->
...
<ListBox Name="listStrategies" SelectedIndex="0"
ItemsSource="{Binding DllList}" SelectedItem="{Binding SelectedStrategy}"
Grid.Column="0" Grid.Row="1" Grid.RowSpan="2"
Width="Auto" MinWidth="120"
Margin="3"
BorderBrush="LightGray" BorderThickness="1">
</ListBox>
...
<!-- More stuff here -->
...
</Grid>
</Window>
When I do this and run the application my list box looks like below which is expected.
The problem is when I try to display a property inside my Strategy objects. My Strategy class contains another class, named StratInfo, which in turn contains a string property, StrategyName. My requirement is to display this string value as listbox item values instead of what you can see above.
So I do the following in my View:
<Window x:Class="PrisonersDilemma.Source.View.ViewPDMain"
xmlns:local="clr-namespace:PrisonersDilemma.Source.View"
DataContext="{Binding Source={StaticResource mainViewModelLocator}, Path=ViewModelPDMain}"
Title="Iterated Prisoner's Dilemma" Height="500" Width="800" MinHeight="500" MinWidth="800">
<Grid Name="gridMain">
...
<!-- More Stuff Here -->
...
<ListBox Name="listStrategies" SelectedIndex="0"
ItemsSource="{Binding DllList}" SelectedItem="{Binding SelectedStrategy}"
Grid.Column="0" Grid.Row="1" Grid.RowSpan="2"
Width="Auto" MinWidth="120"
Margin="3"
BorderBrush="LightGray" BorderThickness="1">
<!-- Added Stuff -->
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Label Name="lblFirstName"
Content="{Binding SelectedStrategy.StratInfo.StrategyName, Mode=OneWay}"
Grid.Column="0"></Label>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
...
<!-- More Stuff Here -->
...
</Grid>
</Window>
When I do this, I expect the list box items to contain a label, and it to display my StrategyName value. However, I get a listbox which contains 25 items (I have 25 DLLs), but all 25 items are empty.
Funny thing is, I tried to bind the SelectedStrategy.StratInfo.StrategyName to a text box Text property, and it worked. That is, when I click any empty listbox item, it displays the StrategyName in the text box. Please refer to the following figure. You can see that the listbox contains items but the content values aren't displayed. In addition, to the right, the Strategy Name text box is a text box where I have bound the SelectedStrategy.StratInfo.StrategyName and it displays the correct value on item select event.
I have done this exact same thing in a simpler project, and it works just fine. I can't figure out what I'm doing wrong here.
Any thoughts?
Your binding in the data template is incorrect. The data context within the data template is an item in the DllList which is of type Strategy. So your Label should be like so:
<Label Name="lblFirstName"
Content="{Binding StratInfo.StrategyName, Mode=OneWay}"
Grid.Column="0"/>

Display images from Assets with JSON - Windows Phone 8

I am making a WP8 application with a lot of local content in my Assets folder. So I am using a JSON file stored in the a JSON folder.
I have been able to parse the JSON to C# very easily and now I am trying to display the data in a list. I had no problem with displaying the title but I am unable to display an image, even with the filename I am got.
My images are stored in "Assets/Content/mediaXXX.jpg";
ListViewModel :
public class ListViewModel
{
public string Title { get; set; }
public string Subtitle { get; set; }
public BitmapImage ListImage { get; set; }
}
XAML
<ListBox Margin="0,1,0,0"
Height="730"
x:Name="MainList">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="120"
Width="480">
<StackPanel Orientation="Horizontal">
<Image HorizontalAlignment="Left"
Source="{Binding ListImage}"
Margin="12"
Stretch="UniformToFill"
Width="130"/>
<Grid>
<TextBlock x:Name="ListItemTitle"
Text="{Binding Title}"/>
<TextBlock x:Name="ListItemSubTitle"
Text="{Binding Subtitle}"/>
</Grid>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
And my C# page
BitmapImage image = new BitmapImage(new Uri(#"Assets/Content/" + photo.filename + ".jpg", UriKind.Relative);
l.ListImage = image;
Any idea?
Code should work. Only problems that might occur is your ListBox databinding is incorrectly defined.
I don't see any .ItemsSource = or ItemsSource={Binding some_collection}
Another thing is make sure that photo.filename is returning the correct file.
Set a string debug_string = "Assets/Content/" + photo.filename + ".jpg";
Make sure everything is correct.
Last thing is to make sure the files are actually in the Assets Folder inside the project and its
BuildAction is set to Content
like so

WPF: Update Listbox automatically C#

I have two WPF windows developed using the surface SDK, one that is a data entry form, and the second dispays the data in a listbox. The listbox displays the data perfectly but when I add a new record using the data entry form, the listbox is not updated until I reopen the window. Is there a way to automatically update the listbox through binding or something?
This is the listbox code:
<s:SurfaceListBox Height="673" Margin="0,26,0,31" Name="surfaceListBox1" ItemsSource="{Binding Path={}}" Width="490">
<s:SurfaceListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Width="80" FontSize="8" Content="{Binding Path=item1}"></Label>
<Label Width="80" FontSize="8" Content="{Binding Path=item2}"></Label>
<Label Width="210" FontSize="8" Content="{Binding Path=item3}"></Label>
<Label Width="80" FontSize="8" Content="{Binding Path=item4}"></Label>
<Label Width="60" FontSize="8" Content="{Binding Path=item5, Converter={StaticResource booleanconverter}}"></Label>
</StackPanel>
</DataTemplate>
</s:SurfaceListBox.ItemTemplate>
</s:SurfaceListBox>
I am using Visual C# 2008 and the code to fill the listbox is:
private SHIPS_LOGDataSet ShipData = new SHIPS_LOGDataSet();
private SHIPS_LOGDataSetTableAdapters.MAINTableAdapter taMain = new SHIPS_LOGDataSetTableAdapters.MAINTableAdapter();
private SHIPS_LOGDataSetTableAdapters.TableAdapterManager taManager = new ShipsLogSurface.SHIPS_LOGDataSetTableAdapters.TableAdapterManager();
private void SurfaceWindow_Loaded(object sender, RoutedEventArgs e)
{
this.taMain.Fill(this.ShipData.MAIN);
this.DataContext = from MAIN in this.ShipData.MAIN orderby MAIN.MESSAGE_ID descending select MAIN;
}
The only table in my database is called MAIN.
I'm guessing I might have to use a collection view or similar but don't know how to implement that. Any ideas would be much appreciated. Thanks
INotifyPropertyChanged is an interface which you should implement in your data class (ShipData?). The properties in your data class should look as follows:
private string _myField;
public string MyField {
get { return _myField; }
set { _myField = value; onPropertyChanged(this, "MyField"); }
}
So whenever something in your data class changes (i.e. add/delete/update), it will fire the OnPropertyChanged event.
Your List or ObservableCollection that you use to populate the list listens to this OnPropertyChanged event and will update itself whenever the event is fired.
Try to do it with INotifyPropertyChanged.
surfaceListBox1.Items.Refresh();

Categories