Does Entity Framework incorrectly detect changes to images?
I have a "Person" entity class defined as follows;
public class Person
{
public int Id { get; set; }
public byte[] Photo { get; set; }
}
I have bound the Photo to a PictureBox control on my form using a datasource.
There form also uses a dynamically created bindingNavigator.
I also have written an audit log to populate captured changes
The procedure calls the ObjectContext DetectChanges() and then
var entries = ObjectContext.ObjectStateManager.GetObjectStateEntries()
Which contains an entry showing that the Photo has been modified.
entry.OriginalValues[name] matches entry.CurrentValues[name]
The Column is varbinary(MAX) in SQL Server and the size of the picture files I have loaded are under 1Mb
If I set all of the columns to null the error no longer occurs
The code I use to get the file is
private void LoadPhotoButton_Click(object sender, EventArgs e)
{
using (var dlg = new OpenFileDialog())
{
dlg.Filter = "JPEG files |*.jpg";
if (dlg.ShowDialog() == DialogResult.OK)
{
PhotoPictureBox.Image = Image.FromFile(dlg.FileName);
}
}
}
I note here that hex zero can be inserted as padding characters when these fields are involved in string conversion.... could the binding be doing that somehow?
If I delete the picturebox from the form, or even bind the control as a text box instead of a picturebox then the behaviour is correct ( not that a picture bound to a text box is any use )
I am able to work around the problem by not binding directly to the picture box.
Instead I just load it on the BindingSource_CurrentChanged event using
private void BindingSource_CurrentChanged(object sender, EventArgs e)
{
var obj = (Person) BindingSource.Current;
this.PictureBox.Image = byteArrayToImage( obj.Photo);
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
I am using my work around - documented at the end of the question as a make do answer.
Related
I'm trying to display an Image for an object in a table view, I have created a DisplayModel class in order to display the relevant values in the table columns from an observable collection, I have 2 columns containing string values and one integer all of which are displaying fine, I also have an image of the Car I wish to display but it will only display the Image#Hashcode rather than the image itself.
The implementation I currently have is as follows:
The display model class:
private ObjectProperty<Image> image;
private SimpleStringProperty make;
private SimpleStringProperty model;
private SimpleDoubleProperty price;
public DisplayModel(Image image, String make, String model, Double price) {
this.image = new SimpleObjectProperty<>(image);
this.make = new SimpleStringProperty(make);
this.model = new SimpleStringProperty(model);
this.price = new SimpleDoubleProperty(price);
}
public Image getImage() {
return image.get();
}
public void setImage(Image displayImage) {
this.image = new SimpleObjectProperty<>(displayImage);
}
The implementation in the initialise method on the controller for the FXML file:
try {
OutputStream targetFile = new FileOutputStream(s + "\\" + imageUrl);
targetFile.write(fileBytes);
targetFile.close();
File f = new File(s + imageUrl);
image = new Image(f.toURI().toString());
} catch (IOException e) {
e.printStackTrace();
}
Using the ImageView controller and trying to display the same image presents it fine so I'm wondering whether it's do with the ObjectProperty implementation or the TableView control.. I've recently faced a similar and far more common issue of needing to override the toString method to return the actual value rather than the String#HashValue, I wonder whether there is a similar way to resolve this issue.
Any advice would be greatly appreciated, thanks for your time.
This has to do with the updateItem implementation of the TableCell returned by the default cellFactory. This is implemented as follows (ignoring empty cells):
If the item is a Node, display it using setGraphic with the item as parameter. This adds the Node to the scene inside the TableCell.
Otherwise convert the object to text using it's toString method and use setText to display the resulting value as text in the TableCell.
Image is not a subclass of Node; therefore you get the latter behavior.
To change this behavior, you need to use a custom cellFactory that deals with the item type properly:
ItemImage.setCellFactory(col -> new TableCell<Item, Image>() { // assuming model class named Car here; type parameters match the TableColumn
private final ImageView imageView = new ImageView();
{
// set size of ImageView
imageView.setFitHeight(50);
imageView.setFitWidth(80);
imageView.setPreserveRatio(true);
// display ImageView in cell
setGraphic(imageView);
}
#Override
protected void updateItem(Image item, boolean empty) {
super.updateItem(item, empty);
imageView.setImage(item);
}
});
Note that usually you don't keep the graphic for empty cells. I decided to do this in this case to keep the cell size consistent.
Am using radgrid and creating it in aspx but on certain action i add more GridTemplateColumns to the grid.
private void CreateDateColumns(List<DateTime> occurenceList)
{
if (occurenceList != null && occurenceList.Count > 0)
{
int index = 1;
foreach (DateTime occurence in occurenceList)
{
string templateColumnName = occurence.Date.ToShortDateString();
GridTemplateColumn templateColumn = new GridTemplateColumn();
templateColumn.ItemTemplate = new MyTemplate(templateColumnName, index);
grdStudentAttendanceList.MasterTableView.Columns.Add(templateColumn);
templateColumn.HeaderText = templateColumnName;
templateColumn.UniqueName = templateColumnName;
index++;
}
}
}
private class MyTemplate : ITemplate
{
protected RadComboBox rcbAttendance;
private string colname;
private int _index;
public MyTemplate(string cName, int index)
{
colname = cName;
_index = index;
}
public void InstantiateIn(System.Web.UI.Control container)
{
rcbAttendance = new RadComboBox();
rcbAttendance.Items.Add(new RadComboBoxItem("---Select---", "-1"));
rcbAttendance.Items.Add(new RadComboBoxItem("Present", "1"));
rcbAttendance.Items.Add(new RadComboBoxItem("Absent", "2"));
rcbAttendance.Items.Add(new RadComboBoxItem("Leave", "3"));
rcbAttendance.ID = "rcbAttendance" + _index;
container.Controls.Add(rcbAttendance);
}
}
All are fine with creation but when i press save button or any combobox make postback the only dynamically generated columns content disappear and the other columns stay.
What i noticed that columns still in place with headertext but only content are disappeared (in my case content are comboboxes)
After enabling viewstate for grid only header text appear.
What should i do to keep columns contents after postback and get their values ?
When creating template columns programmatically, the grid must be generated completely in the code-behind using the Page_Init event. Then, you must create the templates dynamically in the code-behind and assign them to the ItemTemplate and EditItemTemplate properties of the column. To create a template dynamically, you must define a custom class that implements the ITemplate interface. Then you can assign an instance of this class to the ItemTemplate or EditTemplateTemplate property of the GridTemplateColumn object.
Blockquote
Column templates must be added in the Page_Init event handler, so that the template controls can be added to the ViewState.
Blockquote
Source: Telerik
Basicly, you need to create all GridTemplateColumns in the Page_Init. We had the same problem and this approach fixed it.
I'm trying to implement a Windows Phone 8 App that works with image handling, trying it to port it from a Windows 8 App. But I got stuck quite quickly, at the beginning.
What I want to achieve is to select some pictures from the phone and show them in my app, in a similar way they look in an album. For this, I've tried some MVVM technique, also. But I'm given an error when I'm trying to create a BitmapImage from the file Stream saying I'm out of range...
Here's my model :
public class SelectedPhoto : IDisposable
{
public Stream Data { get; set; }
public string Name { get; set; }
public BitmapImage Image { get; set; }
public SelectedPhoto(string name, Stream data)
{
Name = name;
Data = new MemoryStream();
data.CopyTo(Data);
Image = new BitmapImage();
Image.SetSource(Data); //Here's the Argument Exception.
}
public void Dispose()
{
Data.Dispose();
}
}
So I'm given the exception quite in the constructor... and I use this in code in a PhotoChooserTask like this :
private void PhotoChooserTaskCompleted(object sender, PhotoResult e)
{
if (e.TaskResult == TaskResult.OK)
{
PhotosViewModel.AddPhoto(new SelectedPhoto(e.OriginalFileName, e.ChosenPhoto));
}
}
The Argument Exception says : Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection. But I'm not manipulating the Stream in any way, I just need it as it is to create the BitmapImage from it, as I've looked after some examples.
How can I get the BitmapImage of a selected image file from phone in this case? Or much better, how can I get it directly as a WriteableBitmap? Because later on, I'm planning on doing some pixel manipulation.
Any type of approach is welcome, thank you.
To fix your code, call the Seek method to go back to the beginning of your stream:
public SelectedPhoto(string name, Stream data)
{
Name = name;
Data = new MemoryStream();
data.CopyTo(Data);
Data.Seek(0, SeekOrigin.Begin);
Image = new BitmapImage();
Image.SetSource(Data); //Here's the Argument Exception.
}
That said, why are you duplicating the stream? You could directly use data.
///first I have crated Popular class for storing values
public class Popular
{
public string trk_mnetid,trk_title , art_mnetid, art_name, image_url;
}
/// create popularplaylist class
public partial class PopularPlaylist : PhoneApplicationPage
{
Popular popobj = new Popular();
List<Popular> pop = new List<Popular>();
/* call json parsing it and show only "titles" in List form when i m click on perticular title i need to show details in next screen which i paser and store in popular popularplaylist class.
i use navigationservice call new screen
*/
NavigationService.Navigate(new Uri("/Popular_Module/PopularPlaylist.xaml", System.UriKind.Relative));
}
// plz tell me how to get list data in next screen
Use querystring.
Passing Value: In MainPage.xaml.cs add the following
The easiest way to pass a parameter is just to use a string, something like:
private void btnNavigate_Click(object sender, RoutedEventArgs e)
{
string url=String.Format("/Page1.xaml?parameter={0}",popular);
NavigationService.Navigate(new Uri(url, UriKind.Relative));
}
Getting Value: In Page.xaml.cs add the following
Note: It is important to override the OnNavigatedTo and after that you can use the NavigationContext to get the passed parameter.
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
List<string> parameterValue = NavigationContext.QueryString["parameter"];
}
Another popular syntax to get the value of the parameter is:
List<string> parameter = string.Empty;
if (NavigationContext.QueryString.TryGetValue("parameter", out parameter))
{
//do something with the parameter
}
I have a simple user control in Windows Phone 7 and I want to get access to the querystring collection from the user controls Constructor. I have tried many ways and cannot seem to get acess to the containing XAML's querystring collection.
Essentially I am navigating to the page and the my user control is going to access the querystring value to write the value back to the interface.
Am I missing adding an assembly or reference or something?
I am not sure you should be trying to get at the information from the page's constructor, as it won't necessairly get called every time you land on this page. A better approach is to override the OnNavigatedTo method inherited from PhoneApplicationPage. Looking a little more carefully at your question, you may be trying to do this within a control embedded in the page, in which case you need to get at the Page in order to obtain the navigation information.
Regardless, the NavigationContext property from the page has a QueryString parameter that you can use to access the information you're after.
The following example assumes I have a parameter named "Message" in the query string when navigating to this page:
public partial class MyPage : PhoneApplicationPage
{
// Constructor
public MyPage()
{
InitializeComponent();
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
String navigationMessage;
if (NavigationContext.QueryString.TryGetValue("Message", out navigationMessage))
{
this.textBlock1.Text = navigationMessage;
}
}
}
Sorry about that - I started to get there, and thanks for the clarification. Your best bet then is to walk up the visual tree from your control to find the Page, then you can have at the NavigationContext. In my sample below, I have a button on a custom control within the page, whose click event finds the nav context and looks for a certain navigation parameter - I couldn't tell from the question or your follow-up what would drive the control to "want" to find the content of the query string.
(Note about getting info from the ctor follows the code below)
public partial class WindowsPhoneControl1 : UserControl
{
public WindowsPhoneControl1()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
GetTheQueryString();
}
private void GetTheQueryString()
{
var result = "No Joy";
var page = FindRootPage(this);
if (page != null)
{
if (page.NavigationContext.QueryString.ContainsKey("Param"))
{
result = page.NavigationContext.QueryString["Param"];
}
}
queryStringText.Text = result;
}
private static PhoneApplicationPage FindRootPage(FrameworkElement item)
{
if (item != null && !(item is PhoneApplicationPage))
{
item = FindRootPage(item.Parent as FrameworkElement);
}
return item as PhoneApplicationPage;
}
}
Note that this won't work from the ctor because of how Xaml works...the Xml tag drives the ctor to be called, then properties are set as indicated, then it is added as a child/item/etc in its container. If you do need to get at the context ASAP using this "walk up the tree" technique, handle the Control's Loaded event, by which time the control does have a parent and a tree that can be walked...
public WindowsPhoneControl1()
{
InitializeComponent();
Loaded += WindowsPhoneControl1_Loaded;
}
private void WindowsPhoneControl1_Loaded(Object sender, RoutedEventArgs e)
{
GetTheQueryString();
}
I would add a property to the UserControl subclass that would be set by the page in its OnNavigatedTo() method.