I have an Image element that's bound to an ImageSource element inside a class that I've created. The ImageSource gets updated every time a slider is changed. When I first instantiate my window, the ImageSource is blank until the user loads a file. Once the file is loaded, the image appears and the user can scroll the slider and see the image change. They can then select "OK" on the dialog to save this pattern. This all works fine.
However, if they double-click on the item in the ListView then it will re-open this dialog to make further edits. So, it creates a new dialog and then reloads the pertinent info about the image. However, for whatever reason... the image binding no longer works. I can put a breakpoint on the ImageSource getter and everytime I change the slider, the image does get updated... However, it just doesn't appear the be binding correctly. Why would it bind correctly on the first time the window is opened, but not on subsequent openings. I'll try to lay out my code.
In my .XAML code:
<UserControl x:Class="MyControls.CreatePattern"
x:Name="PatternCreation"
...
d:DesignHeight="160" d:DesignWidth="350">
<Slider Value="{Binding ElementName=PatternCreation, Path=Pattern.ZNorm, Mode=TwoWay}" Maximum="1" Name="Slider" VerticalAlignment="Stretch" />
<Image Name="PatternPreview" Source="{Binding ElementName=PatternCreation, Path=Pattern.WPFSlice}" Stretch="Uniform"></Image>
</UserControl
In my code behind I define the Pattern to be bound:
protected PatternVoxelBased mPattern = new PatternVoxelBased();
public PatternVoxelBased Pattern
{
get { return mPattern ; }
set { mPattern = value; }
}
In my PatternVoxelBased class, I have a WPFSlice and ZNorm properties defined like this:
protected ImageSource mWPFSlice;
public ImageSource WPFSlice
{
get { return mWPFSlice; }
set
{
mWPFSlice = value;
NotifyPropertyChanged("WPFSlice");
}
}
protected double mZNorm = 0.5;
public double ZNorm
{
get { return mZNorm; }
set
{
if (mZNorm == value) return;
mZNorm = value;
NotifyPropertyChanged("ZNorm");
WPFSlice = BuildImageAtZ(mZNorm);
}
}
I have an event to load the dialog window the first time:
private void CreatePattern_Click(object sender, RoutedEventArgs e)
{
CCreateVoxelPattern dlg = new CCreateVoxelPattern();
dlg.DataContext = DataContext;
dlg.CShow(PatternLibraryMenu);
}
My ListView Double-Click function to reload the dialog window:
private void ListViewPatternLibrary_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
PatternVoxelBased item = ((ListView)sender).SelectedValue as PatternVoxelBased;
CCreateVoxelPattern dlg = new CCreateVoxelPattern();
dlg.DataContext = DataContext;
dlg.Main.Pattern = item;
dlg.Main.LoadPattern();
dlg.CShow(PatternLibraryMenu);
}
public void LoadPattern()
{
if (Pattern == null) return;
Pattern.WPFSlice = Pattern.BuildImageAtZ(Pattern.ZNorm);
}
In your class where this is
protected PatternVoxelBased mPattern = new PatternVoxelBased();
public PatternVoxelBased Pattern
{
get { return mPattern ; }
set { mPattern = value; }
}
you have to implement INotifyPropertyChanged.
Example
public class YourClass: INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
{
PropertyChanged(this, e);
}
}
protected PatternVoxelBased mPattern = new PatternVoxelBased();
public PatternVoxelBased Pattern
{
get { return mPattern ; }
set { mPattern = value; OnPropertyChanged(new PropertyChangedEventArgs("Pattern"));}
}
}
EDIT
In your Pattern-class, you have to implement that too on every Property.
Related
when i navigate to the new page where it should display the text, it appears empty
The Xaml code i have
xmlns:vm="using:Estimation"
<Page.DataContext>
<vm:PlayerClass/>
</Page.DataContext>
this is the textBlock im trying to bind the data too.
<TextBlock x:Name="PlayerOne"
Text="{Binding PlayerOneName}"
/>
The Class im binding is as follows
public class PlayerClass :INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertChanged(String info)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
private string name;
public string PlayerOneName { get { return this.name; }
set { this.name = value ;
NotifyPropertChanged(PlayerOneName); } }
}}
and the class im changing the content in the text box is
private void StartButton_Click(object sender, RoutedEventArgs e)
{
if (PlayerOneTextBox.Text == EnterNameText ||
PlayerTwoTextBox.Text == EnterNameText ||
PlayerThreeTextBox.Text == EnterNameText ||
PlayerFourTextBox.Text == EnterNameText)
{
MessageDialog msgBox = new MessageDialog("Please Enter All Names Before Continuing");
msgBox.ShowAsync();
}
else
{
// playerNames.PropertyChanged += new DependencyPropertyChangedEventHandler(playerNames_PropertyChanged);
this.DataContex.PlayerOneName = PlayerOneTextBox.Text;
MessageDialog msgBox = new MessageDialog(playerNames.PlayerOneName);
msgBox.ShowAsync();
playerNames.PlayerTwoName = PlayerTwoTextBox.Text;
playerNames.PlayerThreeName = PlayerTwoTextBox.Text;
playerNames.PlayerFourName = PlayerFourTextBox.Text;
Frame.Navigate(typeof(NewRoundPage));
}
}
In the constructor set the name
public PlayerClass ()
{
PlayerOneName = "Jabba De Hutt";
}
Also set a fallback value to provide an indicator of a failed binding situation:
Text="{Binding PlayerOneName, FallBack=Unknown}"
The navigate should not change the datacontext of the textbox, change the viewmodel instead
protected override void OnNavigatedTo(NavigationEventArgs e)
{
var PlayerNames = e.Parameter as PlayerClass;
this.DataContext.PlayerOneName = PlayerNames.PlayerOneName;
}
I don't understand why my rectangles are not being shown.
I made the xaml, and data binded the canvas, and init properly.
What am I missing such that it only shows a blank screen.
It should show a digital figure 8.
MODEL:
namespace Final
{
class Model : INotifyPropertyChanged
{
// define our property chage event handler, part of data binding
public event PropertyChangedEventHandler PropertyChanged;
// implements method for data binding to any and all properties
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private double _topTopHorizontal;
public double topTopHorizontal
{
get { return _topTopHorizontal; }
set
{
_topTopHorizontal = value;
OnPropertyChanged("topTopHorizontal");
}
}
private double _leftTopHorizontal;
public double leftTopHorizontal
{
get { return _leftTopHorizontal; }
set
{
_leftTopHorizontal = value;
OnPropertyChanged("leftTopHorizontal");
}
}
public void initModel()
{
topTopHorizontal = 50;
leftTopHorizontal = 50;
}
}
}
Main
public partial class MainWindow : Window
{
private Model model;
public MainWindow()
{
InitializeComponent();
}
private void WindowLoaded(object sender, RoutedEventArgs e)
{
// create an instance of our Model
model = new Model();
model.initModel();
}
}
}
You haven't set the DataContext for this window.
In constructor add:
public MainWindow()
{
InitializeComponent();
model = new Model();
DataContext = model;
}
Therefor, your window can access "leftTopHorizontal" and "topTopHorizontal".
And in your xaml change:
Canvas.Top ="{Binding topTopHorizontal}"
Canvas.Left="{Binding leftTopHorizontal}"
with:
Canvas.Top ="{Binding model.topTopHorizontal}"
Canvas.Left="{Binding model.leftTopHorizontal}"
my concern is to highlight a selected item in my LongListSelector
when the user taps on it.
I tried this solution: http://code.msdn.microsoft.com/windowsapps/Highlight-a-selected-item-30ced444#content
But i still have a problem.
In my project, the LongListSelector is filled up with 90~100 items and if i tap on the xth element, the (x+20)th, the (x+40)th, the (x+60)th, the (x+80)th... get highlighted too. How is that possible? What does cause this?
I tried to debug, and what i noticed is that "userControlList" (see the MyLongListSelector1_SelectionChanged event handler by following the link above) has 20 elements after the execution of "GetItemsRecursive", and not 90~100 as i, at least, expected.
If you can't solve this, then does anyone know how to actually highlight selected items in LongListSelector? (using Listbox instead is not an option)
How about we write you a better one that is much easier to understand? Plus you can have any combination of highlight colors? I use this for a few of my apps. All it does is it binds the background color to the class as well. If it is selected it returns the highlight color of the class if not it returns the non highlight color.
Sample Data Point - as you can see you can set a highlight color and a no highlight color
public class sample_data : INotifyPropertyChanged
{
// Create the OnPropertyChanged method to raise the event
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(name));
}
}
public sample_data(string name)
{
this.Name = name;
this.IsSelected = false;
this.NonHighlightColor = new SolidColorBrush(Colors.Transparent);
this.HighLightColor = new SolidColorBrush(Colors.Red);
}
public string Name { get; set; }
private bool _is_selected;
public bool IsSelected
{
get { return _is_selected; }
set
{
_is_selected = value;
OnPropertyChanged("HighlightBackgroundColor");
}
}
public SolidColorBrush HighlightBackgroundColor
{
get { if (IsSelected) return HighLightColor; else return NonHighlightColor; }
}
private SolidColorBrush HighLightColor{ get; set; }
private SolidColorBrush NonHighlightColor { get; set; }
}
Lets create the ObservableCollection and set the LongListSelector's ItemSource.
private ObservableCollection<sample_data> CreateSampleData()
{
ObservableCollection<sample_data> sd = new ObservableCollection<sample_data>();
sd.Add(new sample_data("Bob"));
sd.Add(new sample_data("Dan"));
sd.Add(new sample_data("Kate"));
sd.Add(new sample_data("Bart"));
sd.Add(new sample_data("Sanders"));
sd.Add(new sample_data("Dog"));
return sd;
}
// Constructor
public MainPage()
{
InitializeComponent();
mylonglist.ItemsSource = CreateSampleData();
}
Now for the XAML
<phone:LongListSelector x:Name="mylonglist" SelectionChanged="mylonglist_SelectionChanged">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Background="{Binding HighlightBackgroundColor}" Height="100">
<TextBlock Text="{Binding Name}"></TextBlock>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>
Code for the Selection Change
private void mylonglist_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
try
{
LongListSelector ls = sender as LongListSelector;
sample_data selected_item = ls.SelectedItem as sample_data;
// unselected the previous selections
foreach (sample_data sd in ls.ItemsSource)
{
if (sd != selected_item)
{
sd.IsSelected = false;
}
}
// set the selected item (this will cause the background color to change)
selected_item.IsSelected = true;
}
catch (Exception ex)
{
string error = ex.Message;
}
}
There you have it, now you can highlight with any colors and with custom colors for each item without messing with the messy VisualState Manager.
So here I am again, asking a very similar question to yesterday. I re-factored my project in order to better follow the MVVM pattern. Now my binding is no longer working as it was yesterday. I am trying to bind the visibility of a dock panel to a button. Here is some of my code:
ViewModel:
public class SelectWaferButtonViewModel : INotifyPropertyChanged
{
private bool isClicked;
public SelectWaferButtonViewModel()
{
isClicked = false;
}
public bool IsControlVisible
{
get
{
return isClicked;
}
set
{
isClicked = value;
OnPropertyChanged("IsControlVisible");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnButtonClick()
{
if (isClicked)
{
IsControlVisible = false;
}
else
{
IsControlVisible = true;
}
}
protected virtual void OnPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
XAML:
<Window.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisConverter"/>
<local:SelectWaferButtonViewModel x:Key="SelectWaferButton" />
<local:WaferTrackerWindowViewModel x:Key="WindowViewModel" />
</Window.Resources>
<DockPanel
Name="tvwDockPanel"
DataContext="{StaticResource SelectWaferButton}"
Width="225"
Visibility="{Binding IsControlVisible, Mode=TwoWay,
FallbackValue=Collapsed,
Converter={StaticResource BoolToVisConverter}}"
DockPanel.Dock="Left">
</DockPanel>
My BoolToVisConverter:
public class BoolToVisibilityConverter : IValueConverter
{
public BoolToVisibilityConverter() { }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
bool bValue = (bool) value;
if (bValue)
{
return Visibility.Visible;
}
else
{
return Visibility.Collapsed;
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
Visibility visibility = (Visibility) value;
if (visibility == Visibility.Visible)
{
return true;
}
else
{
return false;
}
}
}
I apologize for a question that is similar to yesterday, but I am struggling with this MVVM stuff since I am quite new to WPF. Any help will be much appreciated.
Thanks in advanced,
EDIT:
Here is some extra code snippets for further reference:
public class WaferTrackerWindowViewModel :INotifyPropertyChanged
{
private SelectWaferButtonViewModel btnSelectWaferViewModel;
public event PropertyChangedEventHandler PropertyChanged;
private DelegateCommand exitCommand;
private DelegateCommand expandPanelCommand;
private DelegateCommand selectWaferCommand;
public WaferTrackerWindowViewModel()
{
this.InstantiateObjects();
initThread.RunWorkerAsync();
}
public string SelectedWafer
{
get
{
return selectedWafer;
}
set
{
selectedWafer = value;
}
}
public ICommand ExitCommand
{
get
{
if (exitCommand == null)
{
exitCommand = new DelegateCommand(Exit);
}
return exitCommand;
}
}
public ICommand ExpandPanelCommand
{
get
{
if (expandPanelCommand == null)
{
expandPanelCommand = new DelegateCommand(ExpandPanel);
}
return expandPanelCommand;
}
}
public ICommand SelectWaferCommand
{
get
{
if (selectWaferCommand == null)
{
selectWaferCommand = new DelegateCommand(SelectWafer);
}
return selectWaferCommand;
}
}
private void InstantiateObjects()
{
btnSelectWaferViewModel = new SelectWaferButtonViewModel();
initThread = new BackgroundWorker();
}
private void ExpandPanel()
{
btnSelectWaferViewModel.OnButtonClick();
}
private void SelectWafer()
{
//Does Nothing Yet
}
private void Exit()
{
Application.Current.Shutdown();
}
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
private void InitThread_DoWork(object sender, DoWorkEventArgs e)
{
TreeViewPresenter tvwPresenter = new TreeViewPresenter();
tvwPresenter.WaferList = DataLibrary.GetWaferList();
}
private void InitThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
tvwPresenter.TreeView.DataContext = tvwPresenter.ProcessesAndWafers;
tvwPresenter.WaferListCache = tvwPresenter.ProcessesAndWafers;
tvwPresenter.ProcessArray = tvwPresenter.WaferListCache.ToArray();
}
}
When the "expand panel" button gets clicked, it calls the ExpandPanel command, which routes the execution to the method "private void ExpandPanel()" in this same class. Then, in the ExpandPanel() method, it calls the OnButtonClick() method on the btnSelectWaferViewModel object, which will change the IsControlVisible property. This change should then be reflected onto the bound dock panel, but this is not happening
Kyle
(1) ViewModel should be in the Window.DataContext section, not the Window.Resources section.
(2) In your view model, make your IsControlVisible property a System.Windows.Visibility, rather than a Boolean, then you don't need a converter.
(3) I don't see any way for OnButtonClick to fire, and it really needs to be set up with ICommand interface.
(4) You don't need to implement ConvertBack because the Visibility property you're binding to is one way by definition. There is no way for the user to set the visibility to false.
(5) Don't mix accessing IsClicked and it's accessor IsControlVisible. Always use the Accessor in MVVM, because you run the risk of accidentally setting IsClicked which won't activate OnPropertyChanged.
All in all, you're pretty close. Make sure to keep an eye on your "Output" window, it will tell you if a binding is failing for some reason. But yeah, hang in there!
So when you do this:
<Window.Resources>
<local:SelectWaferButtonViewModel x:Key="SelectWaferButton" />
</Window.Resources>
WPF will create a new instance of the SelectWaferButtonViewModel and add it to it's resources. You then bind to this by setting the DataContext using the StaticResource with the key.
However, if you are then creating another SelectWaferButtonViewModel in your code behind and linking up your command to that instance, then it's not the same instance, so changes to the properties of this unbound instance won't effect your UI. There are a couple of ways around it. You can either a) create a single SelectWaferButtonViewModel in the code behind as a property and then bind to that in XAML, or b) Declare your SelectWaferButtonViewModel in XAML as you currently have it and then retrieve that instance in your code behind, like this:
SelectWaferButtonViewModel swbvm = (SelectWaferButtonViewModel)this.FindResource("SelectWaferButton");
Edit: So after seeing your last edit, if you want to go with a) then I would suggest you expose btnSelectWaferViewModel as a property in your WaferTrackerWindowViewModel and then bind to that property with the DataContext of your Window set to the WaferTrackerWindowViewModel instance. So you end up with something like:
<DockPanel
Name="tvwDockPanel"
Width="225"
Visibility="{Binding MyButton.IsControlVisible,
Converter={StaticResource BoolToVisConverter}}"
DockPanel.Dock="Left">
</DockPanel>
and:
public class WaferTrackerWindowViewModel :INotifyPropertyChanged
{
private SelectWaferButtonViewModel btnSelectWaferViewModel;
public SelectWaferButtonViewModel MyButton
{
get { return btnSelectWaferViewModel; }
set
{
btnSelectWaferViewModel = value;
OnPropertyChanged("MyButton");
}
}
//......
I have a page that already has a DataContext.
When i change the pivot item, I need to bind another list to another collection.
How to achieve this?
Here is the first DataContext that shows first pivotitem info.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
if (NavigationContext.QueryString.TryGetValue("id", out _embarqueId))
{
String json = JsonConvert.SerializeObject(_embarqueId);
using (IntrepService service = new IntrepService())
{
String retornojson = service.ObterDetalhesEmbarque(json);
EmbarqueAtual = JsonConvert.DeserializeObject<EmbarqueViewModel>(retornojson);
DataContext = EmbarqueAtual;
}
VerificaConclusao();
}
}
Then I try to load the second collection to the listbox, but doesn't work:
private void Pivot_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!_itemsareloaded && ((PivotItem)pivot.SelectedItem).Header.Equals("itens"))
{
using (IntrepService service = new IntrepService())
{
String json = JsonConvert.SerializeObject(_embarqueId);
var retorno = service.ObterItensEmbarque(json);
ItensDoEmbarque = JsonConvert.DeserializeObject<ObservableCollection<ItemDeEmbarqueViewModel>>(retorno);
lstItens.DataContext = ItensDoEmbarque;
}
}
}
You should have one ViewModel to hold all of your data that you want to bind to. Set this ViewModel as your datacontext.
public class ViewModel : INotifyPropertyChanged
{
private ObservableCollection<ItemDeEmbarqueViewModel> _itensDoEmbarque;
private EmbarqueViewModel _embarqueAtual;
public ViewModel()
{
ItensDoEmbarque = new ObservableCollection<ItemDeEmbarqueViewModel>();
}
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<ItemDeEmbarqueViewModel> ItensDoEmbarque
{
get { return _itensDoEmbarque; }
set
{
_itensDoEmbarque= value;
OnPropertyChanged("ItensDoEmbarque");
}
}
public EmbarqueViewModel EmbarqueAtual
{
get { return _embarqueAtual; }
set
{
_embarqueAtual = value;
OnPropertyChanged("EmbarqueAtual");
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Within your OnNavigatedTo method set both of the properties and set the DataContext to be this object. You xaml would need to change to bind to the properties of these items instead of {Binding}
You can set the collections that the PivotItem will be bound to ahead of time without worry of rendering delay. PivotItems delay rendering until they are shown.